| |
| |
| |
| |
| |
| |
|
|
| #include "ds4_layer_pack.h" |
|
|
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
|
|
| int ds4_compute_layer_placement(const size_t *entry_bytes, |
| int n_entries, |
| const ds4_layer_pack_config *cfg, |
| int *device_for_entry) { |
| if (!entry_bytes || !cfg || !device_for_entry) return 1; |
| if (n_entries < 0) return 2; |
| if (cfg->n_gpus < 0 || cfg->n_gpus > DS4_LAYER_PACK_MAX_GPUS) return 3; |
|
|
| |
| size_t budget[DS4_LAYER_PACK_MAX_GPUS]; |
| for (int d = 0; d < cfg->n_gpus; d++) { |
| budget[d] = cfg->gpu_budget_bytes[d]; |
| } |
|
|
| int d = 0; |
| for (int e = 0; e < n_entries; e++) { |
| |
| |
| while (d < cfg->n_gpus && entry_bytes[e] > budget[d]) { |
| d++; |
| } |
| if (d < cfg->n_gpus) { |
| device_for_entry[e] = d; |
| budget[d] -= entry_bytes[e]; |
| } else { |
| device_for_entry[e] = DS4_LAYER_PACK_CPU; |
| |
| |
| } |
| } |
| return 0; |
| } |
|
|
| |
| |
| static void append_pseudo_layer_tags(char *buf, size_t buflen, |
| const int *device_for_entry, |
| int tier, |
| int n_entries, |
| int n_layers) { |
| |
| if (n_entries > 0 && device_for_entry[0] == tier) { |
| strncat(buf, " + embedding", buflen - strlen(buf) - 1); |
| } |
| if (n_entries > 1 && n_layers + 1 < n_entries && |
| device_for_entry[n_layers + 1] == tier) { |
| strncat(buf, " + output head", buflen - strlen(buf) - 1); |
| } |
| } |
|
|
| |
| |
| static int print_layer_range_for_tier(FILE *out, const int *device_for_entry, |
| int tier, int n_entries, int n_layers) { |
| |
| |
| int first = -1; |
| int last = -1; |
| for (int i = 1; i <= n_layers && i < n_entries; i++) { |
| if (device_for_entry[i] == tier) { |
| if (first < 0) first = i - 1; |
| last = i - 1; |
| } |
| } |
| if (first < 0) { |
| fprintf(out, "(no transformer layers)"); |
| return 0; |
| } |
| if (first == last) { |
| fprintf(out, "layer %d", first); |
| } else { |
| fprintf(out, "layers %d-%d", first, last); |
| } |
| return 1; |
| } |
|
|
| void ds4_layer_pack_print(FILE *out, |
| const int *device_for_entry, |
| int n_entries, |
| int n_layers, |
| const size_t *entry_bytes, |
| const size_t *gpu_used_bytes, |
| const size_t *gpu_budget_bytes, |
| int n_gpus) { |
| if (!out || !device_for_entry) return; |
| (void)entry_bytes; |
|
|
| fprintf(out, "multi-GPU layout:\n"); |
| for (int d = 0; d < n_gpus; d++) { |
| fprintf(out, " GPU%d: ", d); |
| int have_layers = print_layer_range_for_tier(out, device_for_entry, |
| d, n_entries, n_layers); |
| |
| char tags[64]; |
| tags[0] = '\0'; |
| append_pseudo_layer_tags(tags, sizeof(tags), device_for_entry, d, |
| n_entries, n_layers); |
| if (tags[0]) { |
| if (!have_layers) { |
| |
| |
| |
| |
| } |
| fprintf(out, "%s", tags); |
| } |
| |
| if (gpu_used_bytes && gpu_budget_bytes) { |
| const double used_gb = (double)gpu_used_bytes[d] / 1073741824.0; |
| const double budget_gb = (double)gpu_budget_bytes[d] / 1073741824.0; |
| |
| fprintf(out, " (%.1f / %.1f GB)", used_gb, budget_gb); |
| } |
| fputc('\n', out); |
| } |
| |
| int cpu_present = 0; |
| for (int i = 0; i < n_entries; i++) { |
| if (device_for_entry[i] == DS4_LAYER_PACK_CPU) { cpu_present = 1; break; } |
| } |
| if (cpu_present) { |
| fprintf(out, " CPU : "); |
| int have_layers = print_layer_range_for_tier(out, device_for_entry, |
| DS4_LAYER_PACK_CPU, |
| n_entries, n_layers); |
| char tags[64]; |
| tags[0] = '\0'; |
| append_pseudo_layer_tags(tags, sizeof(tags), device_for_entry, |
| DS4_LAYER_PACK_CPU, n_entries, n_layers); |
| if (tags[0]) { |
| (void)have_layers; |
| fprintf(out, "%s", tags); |
| } |
| fputc('\n', out); |
| } |
| } |
|
|