#include #include #include #include #include #include #include #include #include static const volatile float infinity = INFINITY; static struct cpuinfo_package static_package = { }; static struct cpuinfo_cache static_x86_l3 = { .size = 2 * 1024 * 1024, .associativity = 16, .sets = 2048, .partitions = 1, .line_size = 64, }; void cpuinfo_emscripten_init(void) { struct cpuinfo_processor* processors = NULL; struct cpuinfo_core* cores = NULL; struct cpuinfo_cluster* clusters = NULL; struct cpuinfo_cache* l1i = NULL; struct cpuinfo_cache* l1d = NULL; struct cpuinfo_cache* l2 = NULL; const bool is_x86 = signbit(infinity - infinity); int logical_cores_count = emscripten_num_logical_cores(); if (logical_cores_count <= 0) { logical_cores_count = 1; } uint32_t processor_count = (uint32_t) logical_cores_count; uint32_t core_count = processor_count; uint32_t cluster_count = 1; uint32_t big_cluster_core_count = core_count; uint32_t processors_per_core = 1; if (is_x86) { if (processor_count % 2 == 0) { processors_per_core = 2; core_count = processor_count / 2; big_cluster_core_count = core_count; } } else { /* Assume ARM/ARM64 */ if (processor_count > 4) { /* Assume big.LITTLE architecture */ cluster_count = 2; big_cluster_core_count = processor_count >= 8 ? 4 : 2; } } uint32_t l2_count = is_x86 ? core_count : cluster_count; processors = calloc(processor_count, sizeof(struct cpuinfo_processor)); if (processors == NULL) { cpuinfo_log_error("failed to allocate %zu bytes for descriptions of %"PRIu32" logical processors", processor_count * sizeof(struct cpuinfo_processor), processor_count); goto cleanup; } cores = calloc(processor_count, sizeof(struct cpuinfo_core)); if (cores == NULL) { cpuinfo_log_error("failed to allocate %zu bytes for descriptions of %"PRIu32" cores", processor_count * sizeof(struct cpuinfo_core), processor_count); goto cleanup; } clusters = calloc(cluster_count, sizeof(struct cpuinfo_cluster)); if (clusters == NULL) { cpuinfo_log_error("failed to allocate %zu bytes for descriptions of %"PRIu32" clusters", cluster_count * sizeof(struct cpuinfo_cluster), cluster_count); goto cleanup; } l1i = calloc(core_count, sizeof(struct cpuinfo_cache)); if (l1i == NULL) { cpuinfo_log_error("failed to allocate %zu bytes for descriptions of %"PRIu32" L1I caches", core_count * sizeof(struct cpuinfo_cache), core_count); goto cleanup; } l1d = calloc(core_count, sizeof(struct cpuinfo_cache)); if (l1d == NULL) { cpuinfo_log_error("failed to allocate %zu bytes for descriptions of %"PRIu32" L1D caches", core_count * sizeof(struct cpuinfo_cache), core_count); goto cleanup; } l2 = calloc(l2_count, sizeof(struct cpuinfo_cache)); if (l2 == NULL) { cpuinfo_log_error("failed to allocate %zu bytes for descriptions of %"PRIu32" L2 caches", l2_count * sizeof(struct cpuinfo_cache), l2_count); goto cleanup; } static_package.processor_count = processor_count; static_package.core_count = core_count; static_package.cluster_count = cluster_count; if (is_x86) { strncpy(static_package.name, "x86 vCPU", CPUINFO_PACKAGE_NAME_MAX); } else { strncpy(static_package.name, "ARM vCPU", CPUINFO_PACKAGE_NAME_MAX); } for (uint32_t i = 0; i < core_count; i++) { for (uint32_t j = 0; j < processors_per_core; j++) { processors[i * processors_per_core + j] = (struct cpuinfo_processor) { .smt_id = j, .core = cores + i, .cluster = clusters + (uint32_t) (i >= big_cluster_core_count), .package = &static_package, .cache.l1i = l1i + i, .cache.l1d = l1d + i, .cache.l2 = is_x86 ? l2 + i : l2 + (uint32_t) (i >= big_cluster_core_count), .cache.l3 = is_x86 ? &static_x86_l3 : NULL, }; } cores[i] = (struct cpuinfo_core) { .processor_start = i * processors_per_core, .processor_count = processors_per_core, .core_id = i, .cluster = clusters + (uint32_t) (i >= big_cluster_core_count), .package = &static_package, .vendor = cpuinfo_vendor_unknown, .uarch = cpuinfo_uarch_unknown, .frequency = 0, }; l1i[i] = (struct cpuinfo_cache) { .size = 32 * 1024, .associativity = 4, .sets = 128, .partitions = 1, .line_size = 64, .processor_start = i * processors_per_core, .processor_count = processors_per_core, }; l1d[i] = (struct cpuinfo_cache) { .size = 32 * 1024, .associativity = 4, .sets = 128, .partitions = 1, .line_size = 64, .processor_start = i * processors_per_core, .processor_count = processors_per_core, }; if (is_x86) { l2[i] = (struct cpuinfo_cache) { .size = 256 * 1024, .associativity = 8, .sets = 512, .partitions = 1, .line_size = 64, .processor_start = i * processors_per_core, .processor_count = processors_per_core, }; } } if (is_x86) { clusters[0] = (struct cpuinfo_cluster) { .processor_start = 0, .processor_count = processor_count, .core_start = 0, .core_count = core_count, .cluster_id = 0, .package = &static_package, .vendor = cpuinfo_vendor_unknown, .uarch = cpuinfo_uarch_unknown, .frequency = 0, }; static_x86_l3.processor_count = processor_count; } else { clusters[0] = (struct cpuinfo_cluster) { .processor_start = 0, .processor_count = big_cluster_core_count, .core_start = 0, .core_count = big_cluster_core_count, .cluster_id = 0, .package = &static_package, .vendor = cpuinfo_vendor_unknown, .uarch = cpuinfo_uarch_unknown, .frequency = 0, }; l2[0] = (struct cpuinfo_cache) { .size = 1024 * 1024, .associativity = 8, .sets = 2048, .partitions = 1, .line_size = 64, .processor_start = 0, .processor_count = big_cluster_core_count, }; if (cluster_count > 1) { l2[1] = (struct cpuinfo_cache) { .size = 256 * 1024, .associativity = 8, .sets = 512, .partitions = 1, .line_size = 64, .processor_start = big_cluster_core_count, .processor_count = processor_count - big_cluster_core_count, }; clusters[1] = (struct cpuinfo_cluster) { .processor_start = big_cluster_core_count, .processor_count = processor_count - big_cluster_core_count, .core_start = big_cluster_core_count, .core_count = processor_count - big_cluster_core_count, .cluster_id = 1, .package = &static_package, .vendor = cpuinfo_vendor_unknown, .uarch = cpuinfo_uarch_unknown, .frequency = 0, }; } } /* Commit changes */ cpuinfo_cache[cpuinfo_cache_level_1i] = l1i; cpuinfo_cache[cpuinfo_cache_level_1d] = l1d; cpuinfo_cache[cpuinfo_cache_level_2] = l2; if (is_x86) { cpuinfo_cache[cpuinfo_cache_level_3] = &static_x86_l3; } cpuinfo_processors = processors; cpuinfo_cores = cores; cpuinfo_clusters = clusters; cpuinfo_packages = &static_package; cpuinfo_cache_count[cpuinfo_cache_level_1i] = processor_count; cpuinfo_cache_count[cpuinfo_cache_level_1d] = processor_count; cpuinfo_cache_count[cpuinfo_cache_level_2] = l2_count; if (is_x86) { cpuinfo_cache_count[cpuinfo_cache_level_3] = 1; } cpuinfo_global_uarch = (struct cpuinfo_uarch_info) { .uarch = cpuinfo_uarch_unknown, .processor_count = processor_count, .core_count = core_count, }; cpuinfo_processors_count = processor_count; cpuinfo_cores_count = processor_count; cpuinfo_clusters_count = cluster_count; cpuinfo_packages_count = 1; cpuinfo_max_cache_size = is_x86 ? 128 * 1024 * 1024 : 8 * 1024 * 1024; cpuinfo_is_initialized = true; processors = NULL; cores = NULL; clusters = NULL; l1i = l1d = l2 = NULL; cleanup: free(processors); free(cores); free(clusters); free(l1i); free(l1d); free(l2); }