linux/tools/power/x86/intel-speed-select/isst-display.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Intel dynamic_speed_select -- Enumerate and control features
   4 * Copyright (c) 2019 Intel Corporation.
   5 */
   6
   7#include "isst.h"
   8
   9#define DISP_FREQ_MULTIPLIER 100
  10
  11static void printcpulist(int str_len, char *str, int mask_size,
  12                         cpu_set_t *cpu_mask)
  13{
  14        int i, first, curr_index, index;
  15
  16        if (!CPU_COUNT_S(mask_size, cpu_mask)) {
  17                snprintf(str, str_len, "none");
  18                return;
  19        }
  20
  21        curr_index = 0;
  22        first = 1;
  23        for (i = 0; i < get_topo_max_cpus(); ++i) {
  24                if (!CPU_ISSET_S(i, mask_size, cpu_mask))
  25                        continue;
  26                if (!first) {
  27                        index = snprintf(&str[curr_index],
  28                                         str_len - curr_index, ",");
  29                        curr_index += index;
  30                }
  31                index = snprintf(&str[curr_index], str_len - curr_index, "%d",
  32                                 i);
  33                curr_index += index;
  34                first = 0;
  35        }
  36}
  37
  38static void printcpumask(int str_len, char *str, int mask_size,
  39                         cpu_set_t *cpu_mask)
  40{
  41        int i, max_cpus = get_topo_max_cpus();
  42        unsigned int *mask;
  43        int size, index, curr_index;
  44
  45        size = max_cpus / (sizeof(unsigned int) * 8);
  46        if (max_cpus % (sizeof(unsigned int) * 8))
  47                size++;
  48
  49        mask = calloc(size, sizeof(unsigned int));
  50        if (!mask)
  51                return;
  52
  53        for (i = 0; i < max_cpus; ++i) {
  54                int mask_index, bit_index;
  55
  56                if (!CPU_ISSET_S(i, mask_size, cpu_mask))
  57                        continue;
  58
  59                mask_index = i / (sizeof(unsigned int) * 8);
  60                bit_index = i % (sizeof(unsigned int) * 8);
  61                mask[mask_index] |= BIT(bit_index);
  62        }
  63
  64        curr_index = 0;
  65        for (i = size - 1; i >= 0; --i) {
  66                index = snprintf(&str[curr_index], str_len - curr_index, "%08x",
  67                                 mask[i]);
  68                curr_index += index;
  69                if (i) {
  70                        strncat(&str[curr_index], ",", str_len - curr_index);
  71                        curr_index++;
  72                }
  73        }
  74
  75        free(mask);
  76}
  77
  78static void format_and_print_txt(FILE *outf, int level, char *header,
  79                                 char *value)
  80{
  81        char *spaces = "  ";
  82        static char delimiters[256];
  83        int i, j = 0;
  84
  85        if (!level)
  86                return;
  87
  88        if (level == 1) {
  89                strcpy(delimiters, " ");
  90        } else {
  91                for (i = 0; i < level - 1; ++i)
  92                        j += snprintf(&delimiters[j], sizeof(delimiters) - j,
  93                                      "%s", spaces);
  94        }
  95
  96        if (header && value) {
  97                fprintf(outf, "%s", delimiters);
  98                fprintf(outf, "%s:%s\n", header, value);
  99        } else if (header) {
 100                fprintf(outf, "%s", delimiters);
 101                fprintf(outf, "%s\n", header);
 102        }
 103}
 104
 105static int last_level;
 106static void format_and_print(FILE *outf, int level, char *header, char *value)
 107{
 108        char *spaces = "  ";
 109        static char delimiters[256];
 110        int i;
 111
 112        if (!out_format_is_json()) {
 113                format_and_print_txt(outf, level, header, value);
 114                return;
 115        }
 116
 117        if (level == 0) {
 118                if (header)
 119                        fprintf(outf, "{");
 120                else
 121                        fprintf(outf, "\n}\n");
 122
 123        } else {
 124                int j = 0;
 125
 126                for (i = 0; i < level; ++i)
 127                        j += snprintf(&delimiters[j], sizeof(delimiters) - j,
 128                                      "%s", spaces);
 129
 130                if (last_level == level)
 131                        fprintf(outf, ",\n");
 132
 133                if (value) {
 134                        if (last_level != level)
 135                                fprintf(outf, "\n");
 136
 137                        fprintf(outf, "%s\"%s\": ", delimiters, header);
 138                        fprintf(outf, "\"%s\"", value);
 139                } else {
 140                        for (i = last_level - 1; i >= level; --i) {
 141                                int k = 0;
 142
 143                                for (j = i; j > 0; --j)
 144                                        k += snprintf(&delimiters[k],
 145                                                      sizeof(delimiters) - k,
 146                                                      "%s", spaces);
 147                                if (i == level && header)
 148                                        fprintf(outf, "\n%s},", delimiters);
 149                                else
 150                                        fprintf(outf, "\n%s}", delimiters);
 151                        }
 152                        if (abs(last_level - level) < 3)
 153                                fprintf(outf, "\n");
 154                        if (header)
 155                                fprintf(outf, "%s\"%s\": {", delimiters,
 156                                        header);
 157                }
 158        }
 159
 160        last_level = level;
 161}
 162
 163static void print_package_info(int cpu, FILE *outf)
 164{
 165        char header[256];
 166
 167        snprintf(header, sizeof(header), "package-%d",
 168                 get_physical_package_id(cpu));
 169        format_and_print(outf, 1, header, NULL);
 170        snprintf(header, sizeof(header), "die-%d", get_physical_die_id(cpu));
 171        format_and_print(outf, 2, header, NULL);
 172        snprintf(header, sizeof(header), "cpu-%d", cpu);
 173        format_and_print(outf, 3, header, NULL);
 174}
 175
 176static void _isst_pbf_display_information(int cpu, FILE *outf, int level,
 177                                          struct isst_pbf_info *pbf_info,
 178                                          int disp_level)
 179{
 180        char header[256];
 181        char value[256];
 182
 183        snprintf(header, sizeof(header), "speed-select-base-freq");
 184        format_and_print(outf, disp_level, header, NULL);
 185
 186        snprintf(header, sizeof(header), "high-priority-base-frequency(MHz)");
 187        snprintf(value, sizeof(value), "%d",
 188                 pbf_info->p1_high * DISP_FREQ_MULTIPLIER);
 189        format_and_print(outf, disp_level + 1, header, value);
 190
 191        snprintf(header, sizeof(header), "high-priority-cpu-mask");
 192        printcpumask(sizeof(value), value, pbf_info->core_cpumask_size,
 193                     pbf_info->core_cpumask);
 194        format_and_print(outf, disp_level + 1, header, value);
 195
 196        snprintf(header, sizeof(header), "high-priority-cpu-list");
 197        printcpulist(sizeof(value), value,
 198                     pbf_info->core_cpumask_size,
 199                     pbf_info->core_cpumask);
 200        format_and_print(outf, disp_level + 1, header, value);
 201
 202        snprintf(header, sizeof(header), "low-priority-base-frequency(MHz)");
 203        snprintf(value, sizeof(value), "%d",
 204                 pbf_info->p1_low * DISP_FREQ_MULTIPLIER);
 205        format_and_print(outf, disp_level + 1, header, value);
 206
 207        snprintf(header, sizeof(header), "tjunction-temperature(C)");
 208        snprintf(value, sizeof(value), "%d", pbf_info->t_prochot);
 209        format_and_print(outf, disp_level + 1, header, value);
 210
 211        snprintf(header, sizeof(header), "thermal-design-power(W)");
 212        snprintf(value, sizeof(value), "%d", pbf_info->tdp);
 213        format_and_print(outf, disp_level + 1, header, value);
 214}
 215
 216static void _isst_fact_display_information(int cpu, FILE *outf, int level,
 217                                           int fact_bucket, int fact_avx,
 218                                           struct isst_fact_info *fact_info,
 219                                           int base_level)
 220{
 221        struct isst_fact_bucket_info *bucket_info = fact_info->bucket_info;
 222        char header[256];
 223        char value[256];
 224        int j;
 225
 226        snprintf(header, sizeof(header), "speed-select-turbo-freq");
 227        format_and_print(outf, base_level, header, NULL);
 228        for (j = 0; j < ISST_FACT_MAX_BUCKETS; ++j) {
 229                if (fact_bucket != 0xff && fact_bucket != j)
 230                        continue;
 231
 232                if (!bucket_info[j].high_priority_cores_count)
 233                        break;
 234
 235                snprintf(header, sizeof(header), "bucket-%d", j);
 236                format_and_print(outf, base_level + 1, header, NULL);
 237
 238                snprintf(header, sizeof(header), "high-priority-cores-count");
 239                snprintf(value, sizeof(value), "%d",
 240                         bucket_info[j].high_priority_cores_count);
 241                format_and_print(outf, base_level + 2, header, value);
 242
 243                if (fact_avx & 0x01) {
 244                        snprintf(header, sizeof(header),
 245                                 "high-priority-max-frequency(MHz)");
 246                        snprintf(value, sizeof(value), "%d",
 247                                 bucket_info[j].sse_trl * DISP_FREQ_MULTIPLIER);
 248                        format_and_print(outf, base_level + 2, header, value);
 249                }
 250
 251                if (fact_avx & 0x02) {
 252                        snprintf(header, sizeof(header),
 253                                 "high-priority-max-avx2-frequency(MHz)");
 254                        snprintf(value, sizeof(value), "%d",
 255                                 bucket_info[j].avx_trl * DISP_FREQ_MULTIPLIER);
 256                        format_and_print(outf, base_level + 2, header, value);
 257                }
 258
 259                if (fact_avx & 0x04) {
 260                        snprintf(header, sizeof(header),
 261                                 "high-priority-max-avx512-frequency(MHz)");
 262                        snprintf(value, sizeof(value), "%d",
 263                                 bucket_info[j].avx512_trl *
 264                                         DISP_FREQ_MULTIPLIER);
 265                        format_and_print(outf, base_level + 2, header, value);
 266                }
 267        }
 268        snprintf(header, sizeof(header),
 269                 "speed-select-turbo-freq-clip-frequencies");
 270        format_and_print(outf, base_level + 1, header, NULL);
 271        snprintf(header, sizeof(header), "low-priority-max-frequency(MHz)");
 272        snprintf(value, sizeof(value), "%d",
 273                 fact_info->lp_clipping_ratio_license_sse *
 274                         DISP_FREQ_MULTIPLIER);
 275        format_and_print(outf, base_level + 2, header, value);
 276        snprintf(header, sizeof(header),
 277                 "low-priority-max-avx2-frequency(MHz)");
 278        snprintf(value, sizeof(value), "%d",
 279                 fact_info->lp_clipping_ratio_license_avx2 *
 280                         DISP_FREQ_MULTIPLIER);
 281        format_and_print(outf, base_level + 2, header, value);
 282        snprintf(header, sizeof(header),
 283                 "low-priority-max-avx512-frequency(MHz)");
 284        snprintf(value, sizeof(value), "%d",
 285                 fact_info->lp_clipping_ratio_license_avx512 *
 286                         DISP_FREQ_MULTIPLIER);
 287        format_and_print(outf, base_level + 2, header, value);
 288}
 289
 290void isst_ctdp_display_core_info(int cpu, FILE *outf, char *prefix,
 291                                 unsigned int val)
 292{
 293        char header[256];
 294        char value[256];
 295
 296        snprintf(header, sizeof(header), "package-%d",
 297                 get_physical_package_id(cpu));
 298        format_and_print(outf, 1, header, NULL);
 299        snprintf(header, sizeof(header), "die-%d", get_physical_die_id(cpu));
 300        format_and_print(outf, 2, header, NULL);
 301        snprintf(header, sizeof(header), "cpu-%d", cpu);
 302        format_and_print(outf, 3, header, NULL);
 303
 304        snprintf(value, sizeof(value), "%u", val);
 305        format_and_print(outf, 4, prefix, value);
 306
 307        format_and_print(outf, 1, NULL, NULL);
 308}
 309
 310void isst_ctdp_display_information(int cpu, FILE *outf, int tdp_level,
 311                                   struct isst_pkg_ctdp *pkg_dev)
 312{
 313        char header[256];
 314        char value[256];
 315        int i, base_level = 1;
 316
 317        print_package_info(cpu, outf);
 318
 319        for (i = 0; i <= pkg_dev->levels; ++i) {
 320                struct isst_pkg_ctdp_level_info *ctdp_level;
 321                int j;
 322
 323                ctdp_level = &pkg_dev->ctdp_level[i];
 324                if (!ctdp_level->processed)
 325                        continue;
 326
 327                snprintf(header, sizeof(header), "perf-profile-level-%d",
 328                         ctdp_level->level);
 329                format_and_print(outf, base_level + 3, header, NULL);
 330
 331                snprintf(header, sizeof(header), "cpu-count");
 332                j = get_cpu_count(get_physical_die_id(cpu),
 333                                  get_physical_die_id(cpu));
 334                snprintf(value, sizeof(value), "%d", j);
 335                format_and_print(outf, base_level + 4, header, value);
 336
 337                snprintf(header, sizeof(header), "enable-cpu-mask");
 338                printcpumask(sizeof(value), value,
 339                             ctdp_level->core_cpumask_size,
 340                             ctdp_level->core_cpumask);
 341                format_and_print(outf, base_level + 4, header, value);
 342
 343                snprintf(header, sizeof(header), "enable-cpu-list");
 344                printcpulist(sizeof(value), value,
 345                             ctdp_level->core_cpumask_size,
 346                             ctdp_level->core_cpumask);
 347                format_and_print(outf, base_level + 4, header, value);
 348
 349                snprintf(header, sizeof(header), "thermal-design-power-ratio");
 350                snprintf(value, sizeof(value), "%d", ctdp_level->tdp_ratio);
 351                format_and_print(outf, base_level + 4, header, value);
 352
 353                snprintf(header, sizeof(header), "base-frequency(MHz)");
 354                snprintf(value, sizeof(value), "%d",
 355                         ctdp_level->tdp_ratio * DISP_FREQ_MULTIPLIER);
 356                format_and_print(outf, base_level + 4, header, value);
 357
 358                snprintf(header, sizeof(header),
 359                         "speed-select-turbo-freq");
 360                if (ctdp_level->fact_support) {
 361                        if (ctdp_level->fact_enabled)
 362                                snprintf(value, sizeof(value), "enabled");
 363                        else
 364                                snprintf(value, sizeof(value), "disabled");
 365                } else
 366                        snprintf(value, sizeof(value), "unsupported");
 367                format_and_print(outf, base_level + 4, header, value);
 368
 369                snprintf(header, sizeof(header),
 370                         "speed-select-base-freq");
 371                if (ctdp_level->pbf_support) {
 372                        if (ctdp_level->pbf_enabled)
 373                                snprintf(value, sizeof(value), "enabled");
 374                        else
 375                                snprintf(value, sizeof(value), "disabled");
 376                } else
 377                        snprintf(value, sizeof(value), "unsupported");
 378                format_and_print(outf, base_level + 4, header, value);
 379
 380                snprintf(header, sizeof(header), "thermal-design-power(W)");
 381                snprintf(value, sizeof(value), "%d", ctdp_level->pkg_tdp);
 382                format_and_print(outf, base_level + 4, header, value);
 383
 384                snprintf(header, sizeof(header), "tjunction-max(C)");
 385                snprintf(value, sizeof(value), "%d", ctdp_level->t_proc_hot);
 386                format_and_print(outf, base_level + 4, header, value);
 387
 388                snprintf(header, sizeof(header), "turbo-ratio-limits-sse");
 389                format_and_print(outf, base_level + 4, header, NULL);
 390                for (j = 0; j < 8; ++j) {
 391                        snprintf(header, sizeof(header), "bucket-%d", j);
 392                        format_and_print(outf, base_level + 5, header, NULL);
 393
 394                        snprintf(header, sizeof(header), "core-count");
 395                        snprintf(value, sizeof(value), "%llu", (ctdp_level->buckets_info >> (j * 8)) & 0xff);
 396                        format_and_print(outf, base_level + 6, header, value);
 397
 398                        snprintf(header, sizeof(header),
 399                                "max-turbo-frequency(MHz)");
 400                        snprintf(value, sizeof(value), "%d",
 401                                 ctdp_level->trl_sse_active_cores[j] *
 402                                  DISP_FREQ_MULTIPLIER);
 403                        format_and_print(outf, base_level + 6, header, value);
 404                }
 405                snprintf(header, sizeof(header), "turbo-ratio-limits-avx");
 406                format_and_print(outf, base_level + 4, header, NULL);
 407                for (j = 0; j < 8; ++j) {
 408                        snprintf(header, sizeof(header), "bucket-%d", j);
 409                        format_and_print(outf, base_level + 5, header, NULL);
 410
 411                        snprintf(header, sizeof(header), "core-count");
 412                        snprintf(value, sizeof(value), "%llu", (ctdp_level->buckets_info >> (j * 8)) & 0xff);
 413                        format_and_print(outf, base_level + 6, header, value);
 414
 415                        snprintf(header, sizeof(header),
 416                                "max-turbo-frequency(MHz)");
 417                        snprintf(value, sizeof(value), "%d",
 418                                 ctdp_level->trl_avx_active_cores[j] *
 419                                  DISP_FREQ_MULTIPLIER);
 420                        format_and_print(outf, base_level + 6, header, value);
 421                }
 422
 423                snprintf(header, sizeof(header), "turbo-ratio-limits-avx512");
 424                format_and_print(outf, base_level + 4, header, NULL);
 425                for (j = 0; j < 8; ++j) {
 426                        snprintf(header, sizeof(header), "bucket-%d", j);
 427                        format_and_print(outf, base_level + 5, header, NULL);
 428
 429                        snprintf(header, sizeof(header), "core-count");
 430                        snprintf(value, sizeof(value), "%llu", (ctdp_level->buckets_info >> (j * 8)) & 0xff);
 431                        format_and_print(outf, base_level + 6, header, value);
 432
 433                        snprintf(header, sizeof(header),
 434                                "max-turbo-frequency(MHz)");
 435                        snprintf(value, sizeof(value), "%d",
 436                                 ctdp_level->trl_avx_512_active_cores[j] *
 437                                  DISP_FREQ_MULTIPLIER);
 438                        format_and_print(outf, base_level + 6, header, value);
 439                }
 440                if (ctdp_level->pbf_support)
 441                        _isst_pbf_display_information(cpu, outf, i,
 442                                                      &ctdp_level->pbf_info,
 443                                                      base_level + 4);
 444                if (ctdp_level->fact_support)
 445                        _isst_fact_display_information(cpu, outf, i, 0xff, 0xff,
 446                                                       &ctdp_level->fact_info,
 447                                                       base_level + 4);
 448        }
 449
 450        format_and_print(outf, 1, NULL, NULL);
 451}
 452
 453void isst_ctdp_display_information_start(FILE *outf)
 454{
 455        last_level = 0;
 456        format_and_print(outf, 0, "start", NULL);
 457}
 458
 459void isst_ctdp_display_information_end(FILE *outf)
 460{
 461        format_and_print(outf, 0, NULL, NULL);
 462}
 463
 464void isst_pbf_display_information(int cpu, FILE *outf, int level,
 465                                  struct isst_pbf_info *pbf_info)
 466{
 467        print_package_info(cpu, outf);
 468        _isst_pbf_display_information(cpu, outf, level, pbf_info, 4);
 469        format_and_print(outf, 1, NULL, NULL);
 470}
 471
 472void isst_fact_display_information(int cpu, FILE *outf, int level,
 473                                   int fact_bucket, int fact_avx,
 474                                   struct isst_fact_info *fact_info)
 475{
 476        print_package_info(cpu, outf);
 477        _isst_fact_display_information(cpu, outf, level, fact_bucket, fact_avx,
 478                                       fact_info, 4);
 479        format_and_print(outf, 1, NULL, NULL);
 480}
 481
 482void isst_clos_display_information(int cpu, FILE *outf, int clos,
 483                                   struct isst_clos_config *clos_config)
 484{
 485        char header[256];
 486        char value[256];
 487
 488        snprintf(header, sizeof(header), "package-%d",
 489                 get_physical_package_id(cpu));
 490        format_and_print(outf, 1, header, NULL);
 491        snprintf(header, sizeof(header), "die-%d", get_physical_die_id(cpu));
 492        format_and_print(outf, 2, header, NULL);
 493        snprintf(header, sizeof(header), "cpu-%d", cpu);
 494        format_and_print(outf, 3, header, NULL);
 495
 496        snprintf(header, sizeof(header), "core-power");
 497        format_and_print(outf, 4, header, NULL);
 498
 499        snprintf(header, sizeof(header), "clos");
 500        snprintf(value, sizeof(value), "%d", clos);
 501        format_and_print(outf, 5, header, value);
 502
 503        snprintf(header, sizeof(header), "epp");
 504        snprintf(value, sizeof(value), "%d", clos_config->epp);
 505        format_and_print(outf, 5, header, value);
 506
 507        snprintf(header, sizeof(header), "clos-proportional-priority");
 508        snprintf(value, sizeof(value), "%d", clos_config->clos_prop_prio);
 509        format_and_print(outf, 5, header, value);
 510
 511        snprintf(header, sizeof(header), "clos-min");
 512        snprintf(value, sizeof(value), "%d", clos_config->clos_min);
 513        format_and_print(outf, 5, header, value);
 514
 515        snprintf(header, sizeof(header), "clos-max");
 516        snprintf(value, sizeof(value), "%d", clos_config->clos_max);
 517        format_and_print(outf, 5, header, value);
 518
 519        snprintf(header, sizeof(header), "clos-desired");
 520        snprintf(value, sizeof(value), "%d", clos_config->clos_desired);
 521        format_and_print(outf, 5, header, value);
 522
 523        format_and_print(outf, 1, NULL, NULL);
 524}
 525
 526void isst_clos_display_clos_information(int cpu, FILE *outf,
 527                                        int clos_enable, int type)
 528{
 529        char header[256];
 530        char value[256];
 531
 532        snprintf(header, sizeof(header), "package-%d",
 533                 get_physical_package_id(cpu));
 534        format_and_print(outf, 1, header, NULL);
 535        snprintf(header, sizeof(header), "die-%d", get_physical_die_id(cpu));
 536        format_and_print(outf, 2, header, NULL);
 537        snprintf(header, sizeof(header), "cpu-%d", cpu);
 538        format_and_print(outf, 3, header, NULL);
 539
 540        snprintf(header, sizeof(header), "core-power");
 541        format_and_print(outf, 4, header, NULL);
 542
 543        snprintf(header, sizeof(header), "enable-status");
 544        snprintf(value, sizeof(value), "%d", clos_enable);
 545        format_and_print(outf, 5, header, value);
 546
 547        snprintf(header, sizeof(header), "priority-type");
 548        snprintf(value, sizeof(value), "%d", type);
 549        format_and_print(outf, 5, header, value);
 550
 551        format_and_print(outf, 1, NULL, NULL);
 552}
 553
 554void isst_clos_display_assoc_information(int cpu, FILE *outf, int clos)
 555{
 556        char header[256];
 557        char value[256];
 558
 559        snprintf(header, sizeof(header), "package-%d",
 560                 get_physical_package_id(cpu));
 561        format_and_print(outf, 1, header, NULL);
 562        snprintf(header, sizeof(header), "die-%d", get_physical_die_id(cpu));
 563        format_and_print(outf, 2, header, NULL);
 564        snprintf(header, sizeof(header), "cpu-%d", cpu);
 565        format_and_print(outf, 3, header, NULL);
 566
 567        snprintf(header, sizeof(header), "get-assoc");
 568        format_and_print(outf, 4, header, NULL);
 569
 570        snprintf(header, sizeof(header), "clos");
 571        snprintf(value, sizeof(value), "%d", clos);
 572        format_and_print(outf, 5, header, value);
 573
 574        format_and_print(outf, 1, NULL, NULL);
 575}
 576
 577void isst_display_result(int cpu, FILE *outf, char *feature, char *cmd,
 578                         int result)
 579{
 580        char header[256];
 581        char value[256];
 582
 583        snprintf(header, sizeof(header), "package-%d",
 584                 get_physical_package_id(cpu));
 585        format_and_print(outf, 1, header, NULL);
 586        snprintf(header, sizeof(header), "die-%d", get_physical_die_id(cpu));
 587        format_and_print(outf, 2, header, NULL);
 588        snprintf(header, sizeof(header), "cpu-%d", cpu);
 589        format_and_print(outf, 3, header, NULL);
 590        snprintf(header, sizeof(header), "%s", feature);
 591        format_and_print(outf, 4, header, NULL);
 592        snprintf(header, sizeof(header), "%s", cmd);
 593        if (!result)
 594                snprintf(value, sizeof(value), "success");
 595        else
 596                snprintf(value, sizeof(value), "failed(error %d)", result);
 597        format_and_print(outf, 5, header, value);
 598
 599        format_and_print(outf, 1, NULL, NULL);
 600}
 601