@@ -35,6 +35,9 @@ import type {
3535 SampleFilterSpec ,
3636 ProfileLogsResult ,
3737 ThreadSelectResult ,
38+ CounterSummary ,
39+ CounterListResult ,
40+ CounterInfoResult ,
3841} from './protocol' ;
3942import { truncateFunctionName } from '../../src/profile-query/function-list' ;
4043import { describeSpec } from '../../src/profile-query/filter-stack' ;
@@ -448,9 +451,90 @@ Name: ${result.name}\n`;
448451 output += 'No significant activity.\n' ;
449452 }
450453
454+ if ( result . counters && result . counters . length > 0 ) {
455+ output += `\nCounters (${ result . counters . length } ):\n` ;
456+ for ( const counter of result . counters ) {
457+ output += `${ formatCounterSummaryLine ( counter ) } \n` ;
458+ }
459+ }
460+
451461 return output ;
452462}
453463
464+ function formatCounterStatInline (
465+ stat : CounterSummary [ 'stats' ] [ number ]
466+ ) : string {
467+ const value = stat . carbon
468+ ? `${ stat . formattedValue } (${ stat . carbon } )`
469+ : stat . formattedValue ;
470+ return `${ stat . label } : ${ value } ` ;
471+ }
472+
473+ function formatCounterSummaryLine ( counter : CounterSummary ) : string {
474+ const stats =
475+ counter . stats . length > 0
476+ ? ` - ${ counter . stats . map ( formatCounterStatInline ) . join ( '; ' ) } `
477+ : '' ;
478+ return ` ${ counter . counterHandle } : ${ counter . label } (${ counter . category } )${ stats } [${ counter . rangeSampleCount } samples]` ;
479+ }
480+
481+ /**
482+ * Format a CounterListResult as plain text.
483+ */
484+ export function formatCounterListResult (
485+ result : WithContext < CounterListResult >
486+ ) : string {
487+ const contextHeader = formatContextHeader ( result . context ) ;
488+ if ( result . counters . length === 0 ) {
489+ return `${ contextHeader } \n\nNo counters in this profile.` ;
490+ }
491+ const lines = result . counters . map ( formatCounterSummaryLine ) ;
492+ return `${ contextHeader } \n\nCounters (${ result . counters . length } ):\n${ lines . join ( '\n' ) } ` ;
493+ }
494+
495+ /**
496+ * Format a CounterInfoResult as plain text.
497+ */
498+ export function formatCounterInfoResult (
499+ result : WithContext < CounterInfoResult >
500+ ) : string {
501+ const contextHeader = formatContextHeader ( result . context ) ;
502+ const lines = [
503+ contextHeader ,
504+ '' ,
505+ `Counter ${ result . counterHandle } : ${ result . label } ` ,
506+ ` Name: ${ result . name } ` ,
507+ ` Category: ${ result . category } ` ,
508+ ] ;
509+ if ( result . description ) {
510+ lines . push ( ` Description: ${ result . description } ` ) ;
511+ }
512+ lines . push ( ` Unit: ${ result . unit || '(none)' } ` ) ;
513+ lines . push ( ` Graph type: ${ result . graphType } ` ) ;
514+ lines . push (
515+ ` Main thread: ${ result . mainThreadHandle } (${ result . mainThreadName } )`
516+ ) ;
517+ lines . push (
518+ ` Samples: ${ result . sampleCount } total, ${ result . rangeSampleCount } in current range`
519+ ) ;
520+ if ( result . rangeStart !== null && result . rangeEnd !== null ) {
521+ const zeroAt = result . context . rootRange . start ;
522+ lines . push (
523+ ` Time span: ${ formatDuration ( result . rangeStart - zeroAt ) } → ${ formatDuration ( result . rangeEnd - zeroAt ) } `
524+ ) ;
525+ }
526+ if ( result . stats . length > 0 ) {
527+ lines . push ( ' Stats (current range):' ) ;
528+ for ( const stat of result . stats ) {
529+ const value = stat . carbon
530+ ? `${ stat . formattedValue } (${ stat . carbon } )`
531+ : stat . formattedValue ;
532+ lines . push ( ` ${ stat . label } : ${ value } ` ) ;
533+ }
534+ }
535+ return lines . join ( '\n' ) ;
536+ }
537+
454538/**
455539 * Helper function to format a call tree node recursively.
456540 *
0 commit comments