224 lines
6.2 KiB
C
224 lines
6.2 KiB
C
#include "platform.c"
|
|
|
|
// ----------------------------- Main ---------------------------------------
|
|
int main(int argc, char **argv) {
|
|
char folders[64][MAX_PATHLEN]; // up to 64 input folders
|
|
int folder_count = 0;
|
|
|
|
// -------------------------------
|
|
// Parse arguments
|
|
// -------------------------------
|
|
for (int i = 1; i < argc; ++i) {
|
|
if (folder_count < 64) {
|
|
normalize_path(argv[i]);
|
|
strncpy(folders[folder_count], argv[i], MAX_PATHLEN - 1);
|
|
folders[folder_count][MAX_PATHLEN - 1] = 0;
|
|
folder_count++;
|
|
}
|
|
}
|
|
|
|
// -------------------------------
|
|
// Ask user if no folders provided
|
|
// -------------------------------
|
|
if (folder_count == 0) {
|
|
printf("Enter folders to process (Enter = current folder): ");
|
|
fflush(stdout);
|
|
|
|
char buf[KiB(32)];
|
|
|
|
if (!fgets(buf, sizeof(buf), stdin))
|
|
return 1;
|
|
|
|
buf[strcspn(buf, "\r\n")] = 0;
|
|
|
|
if (buf[0] == 0) {
|
|
strcpy(folders[0], ".");
|
|
folder_count = 1;
|
|
} else {
|
|
folder_count = parse_paths(buf, folders, 64);
|
|
}
|
|
}
|
|
|
|
// Display selected folders
|
|
printf("Processing %d folder(s):\n", folder_count);
|
|
for (int i = 0; i < folder_count; ++i) {
|
|
printf(" - %s\n", folders[i]);
|
|
}
|
|
|
|
// -------------------------------
|
|
// Scanning and total timer init
|
|
// -------------------------------
|
|
timer_init();
|
|
|
|
HiResTimer total_timer;
|
|
HiResTimer scan_timer;
|
|
|
|
timer_start(&total_timer);
|
|
timer_start(&scan_timer);
|
|
|
|
// -------------------------------
|
|
// Creating a general purpose arena
|
|
// -------------------------------
|
|
arena_params params = {
|
|
.reserve_size = GiB(1),
|
|
.commit_size = MiB(16),
|
|
.align = 0,
|
|
.push_size = 0,
|
|
.allow_free_list = true,
|
|
.allow_swapback = false,
|
|
.growth_policy = ARENA_GROWTH_NORMAL,
|
|
.commit_policy = ARENA_COMMIT_LAZY,
|
|
.max_nbre_blocks = 1,
|
|
};
|
|
|
|
mem_arena *gp_arena = arena_create(¶ms);
|
|
|
|
// -------------------------------
|
|
// Detect hardware threads
|
|
// -------------------------------
|
|
// --- Windows: detect PHYSICAL cores (not logical threads) ---
|
|
size_t hw_threads = platform_physical_cores();
|
|
|
|
// Logical threads = CPU cores * 2
|
|
size_t num_threads = hw_threads * 2;
|
|
|
|
printf("Starting thread pool: %zu threads (CPU cores: %zu)\n", num_threads,
|
|
hw_threads);
|
|
printf(" Selected instruction set: %s\n", get_xxhash_instruction_set());
|
|
|
|
// -------------------------------
|
|
// Scanning and hashing
|
|
// -------------------------------
|
|
MPMCQueue dir_queue;
|
|
mpmc_init(&dir_queue, MiB(1));
|
|
|
|
MPMCQueue file_queue;
|
|
mpmc_init(&file_queue, MiB(1));
|
|
|
|
// Starting hash threads
|
|
size_t num_hash_threads = num_threads;
|
|
|
|
WorkerContext workers[num_hash_threads];
|
|
Thread *hash_threads =
|
|
arena_push(&gp_arena, sizeof(Thread) * num_hash_threads, true);
|
|
|
|
for (size_t i = 0; i < num_hash_threads; ++i) {
|
|
workers[i].arena = arena_create(¶ms);
|
|
workers[i].file_queue = &file_queue;
|
|
|
|
if (thread_create(&hash_threads[i], (ThreadFunc)hash_worker, &workers[i]) !=
|
|
0) {
|
|
fprintf(stderr, "Failed to create hash thread %zu\n", i);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
// Starting progress printing thread
|
|
Thread progress_thread_handle;
|
|
if (thread_create(&progress_thread_handle, (ThreadFunc)progress_thread,
|
|
NULL) != 0) {
|
|
fprintf(stderr, "Failed to create progress thread\n");
|
|
exit(1);
|
|
}
|
|
|
|
// Starting scan threads
|
|
size_t num_scan_threads = num_threads;
|
|
|
|
ScannerContext scanners[num_scan_threads];
|
|
Thread *scan_threads =
|
|
arena_push(&gp_arena, sizeof(Thread) * num_scan_threads, true);
|
|
|
|
for (size_t i = 0; i < num_scan_threads; i++) {
|
|
scanners[i].num_threads = num_scan_threads;
|
|
scanners[i].path_arena = arena_create(¶ms);
|
|
scanners[i].meta_arena = arena_create(¶ms);
|
|
scanners[i].dir_queue = &dir_queue;
|
|
scanners[i].file_queue = &file_queue;
|
|
|
|
if (thread_create(&scan_threads[i], (ThreadFunc)scan_worker,
|
|
&scanners[i]) != 0) {
|
|
fprintf(stderr, "Failed to create scan thread %zu\n", i);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
// Initial folder push
|
|
for (int i = 0; i < folder_count; i++) {
|
|
size_t len = strlen(folders[i]) + 1;
|
|
char *path = arena_push(&scanners[0].path_arena, len, false);
|
|
memcpy(path, folders[i], len);
|
|
mpmc_push_work(&dir_queue, path);
|
|
}
|
|
|
|
// Stop scan threads
|
|
thread_wait_multiple(scan_threads, num_scan_threads);
|
|
|
|
for (size_t i = 0; i < num_scan_threads; ++i) {
|
|
thread_close(&scan_threads[i]);
|
|
}
|
|
|
|
mpmc_producers_finished(&file_queue, num_hash_threads);
|
|
|
|
atomic_store(&g_scan_done, 1);
|
|
|
|
arena_free(&gp_arena, (u8 **)&scan_threads,
|
|
sizeof(Thread) * num_scan_threads);
|
|
|
|
double scan_seconds = timer_elapsed(&scan_timer);
|
|
size_t total_found = atomic_load(&g_files_found);
|
|
|
|
printf("\r%*s\r", 120, ""); // clear_console_line
|
|
printf("Completed scanning in %.2f seconds, found %zu files\n\n",
|
|
scan_seconds, total_found);
|
|
|
|
// If no files found
|
|
if (total_found == 0) {
|
|
printf("No files found.\n");
|
|
return 0;
|
|
}
|
|
|
|
// Stop hashing threads
|
|
thread_wait_multiple(hash_threads, num_hash_threads);
|
|
|
|
for (size_t i = 0; i < num_hash_threads; ++i) {
|
|
thread_close(&hash_threads[i]);
|
|
}
|
|
|
|
arena_free(&gp_arena, (u8 **)&hash_threads,
|
|
sizeof(Thread) * num_hash_threads);
|
|
|
|
// Stop progress printing thread
|
|
thread_join(&progress_thread_handle);
|
|
thread_close(&progress_thread_handle);
|
|
|
|
// -------------------------------
|
|
// Export file_hashes.txt
|
|
// -------------------------------
|
|
|
|
FILE *f = fopen(FILE_HASHES_TXT, "wb");
|
|
|
|
for (int i = 0; i < num_threads; i++) {
|
|
mem_arena *arena = workers[i].arena;
|
|
u8 *arena_base =
|
|
(u8 *)arena + ALIGN_UP_POW2(sizeof(mem_arena), arena->align);
|
|
fwrite(arena_base, 1, arena->pos, f);
|
|
}
|
|
|
|
fclose(f);
|
|
|
|
// -------------------------------
|
|
// Print summary
|
|
// -------------------------------
|
|
double total_seconds = timer_elapsed(&total_timer);
|
|
|
|
printf("Completed hashing %zu files\n", total_found);
|
|
|
|
uint64_t total_bytes = (uint64_t)atomic_load(&g_bytes_processed);
|
|
double total_mb = (double)total_bytes / (1024.0 * 1024.0);
|
|
double avg_mbps = total_mb / total_seconds;
|
|
printf("Total: %.2f MB, Average: %.2f MB/s\n", total_mb, avg_mbps);
|
|
printf(" Total time : %.2f seconds\n\n", total_seconds);
|
|
|
|
return 0;
|
|
}
|