| 762 | } |
| 763 | |
| 764 | int cbm_mem_phase_report_json(char *out, size_t size) { |
| 765 | if (!out || size == 0) { |
| 766 | return 0; |
| 767 | } |
| 768 | out[0] = '\0'; |
| 769 | if (!mem_phase_enabled()) { |
| 770 | return 0; |
| 771 | } |
| 772 | mem_phase_slot_t copy[MEM_PHASE_SLOTS]; |
| 773 | int count = 0; |
| 774 | cbm_mutex_lock(&g_mem_phase_mutex); |
| 775 | count = g_mem_phase_count; |
| 776 | memcpy(copy, g_mem_phases, sizeof(copy)); |
| 777 | cbm_mutex_unlock(&g_mem_phase_mutex); |
| 778 | |
| 779 | /* Biggest retainer first — insertion sort, count <= MEM_PHASE_SLOTS. */ |
| 780 | for (int i = 1; i < count; i++) { |
| 781 | mem_phase_slot_t key = copy[i]; |
| 782 | int j = i - 1; |
| 783 | while (j >= 0 && copy[j].bytes < key.bytes) { |
| 784 | copy[j + 1] = copy[j]; |
| 785 | j--; |
| 786 | } |
| 787 | copy[j + 1] = key; |
| 788 | } |
| 789 | |
| 790 | int length = 0; |
| 791 | for (int i = 0; i < count && length >= 0 && (size_t)length < size; i++) { |
| 792 | int written = snprintf(out + length, size - (size_t)length, |
| 793 | "%s{\"label\": \"%s\", \"bytes\": %lld, \"hits\": %lld}", |
| 794 | i == 0 ? "" : ", ", copy[i].label ? copy[i].label : "?", |
| 795 | (long long)copy[i].bytes, (long long)copy[i].hits); |
| 796 | if (written < 0) { |
| 797 | break; |
| 798 | } |
| 799 | length += written; |
| 800 | } |
| 801 | return length > 0 && (size_t)length < size ? length : 0; |
| 802 | } |
| 803 | |
| 804 | /* ── Windows region census (see mem.h) ─────────────────────────────── */ |
| 805 |
no test coverage detected