44
55import * as React from 'react' ;
66import { InView } from 'react-intersection-observer' ;
7- import { Localized } from '@fluent/react' ;
87import { withSize } from 'firefox-profiler/components/shared/WithSize' ;
98import {
109 getStrokeColor ,
1110 getFillColor ,
1211 getDotColor ,
1312} from 'firefox-profiler/profile-logic/graph-color' ;
1413import explicitConnect from 'firefox-profiler/utils/connect' ;
15- import {
16- formatBytes ,
17- formatNumber ,
18- formatPercent ,
19- } from 'firefox-profiler/utils/format-numbers' ;
2014import { bisectionRight } from 'firefox-profiler/utils/bisect' ;
2115import {
2216 getCommittedRange ,
2317 getCounterSelectors ,
24- getPreviewSelection ,
2518 getProfileInterval ,
2619} from 'firefox-profiler/selectors/profile' ;
2720import { getThreadSelectors } from 'firefox-profiler/selectors/per-thread' ;
28- import { Tooltip } from 'firefox-profiler/components/tooltip/Tooltip' ;
29- import { TooltipTrackPower } from 'firefox-profiler/components/tooltip/TrackPower' ;
30- import {
31- TooltipDetails ,
32- TooltipDetail ,
33- TooltipDetailSeparator ,
34- } from 'firefox-profiler/components/tooltip/TooltipDetails' ;
21+ import { TrackCounterTooltip } from './TrackCounterTooltip' ;
3522import { EmptyThreadIndicator } from './EmptyThreadIndicator' ;
36- import { getSampleIndexRangeForSelection } from 'firefox-profiler/profile-logic/profile-data' ;
3723import { assertExhaustiveCheck } from 'firefox-profiler/utils/types' ;
38- import { co2 } from '@tgwf/co2' ;
3924
4025import type {
4126 CounterIndex ,
@@ -44,7 +29,6 @@ import type {
4429 ThreadIndex ,
4530 AccumulatedCounterSamples ,
4631 Milliseconds ,
47- PreviewSelection ,
4832 CssPixels ,
4933 StartEndRange ,
5034 IndexIntoSamplesTable ,
@@ -379,7 +363,6 @@ type StateProps = {
379363 readonly interval : Milliseconds ;
380364 readonly filteredThread : Thread ;
381365 readonly unfilteredSamplesRange : StartEndRange | null ;
382- readonly previewSelection : PreviewSelection | null ;
383366} ;
384367
385368type DispatchProps = { } ;
@@ -393,10 +376,8 @@ type State = {
393376} ;
394377
395378/**
396- * The generic counter track graph component. It renders information from any counters
397- * (eg, Memory, Power, etc.) as a graph in the timeline. It branches on
398- * `display.graphType` for drawing, and on `counter.category`/`counter.name`
399- * for tooltip rendering of known counter types.
379+ * The generic counter track graph component. It renders any counter
380+ * (Memory, Power, etc.) as a graph in the timeline.
400381 */
401382class TrackCounterGraphImpl extends React . PureComponent < Props , State > {
402383 override state = {
@@ -405,8 +386,6 @@ class TrackCounterGraphImpl extends React.PureComponent<Props, State> {
405386 mouseY : 0 ,
406387 } ;
407388
408- _co2 : InstanceType < typeof co2 > | null = null ;
409-
410389 _onMouseLeave = ( ) => {
411390 // This persistTooltips property is part of the web console API. It helps
412391 // in being able to inspect and debug tooltips.
@@ -509,44 +488,14 @@ class TrackCounterGraphImpl extends React.PureComponent<Props, State> {
509488 }
510489 } ;
511490
512- _formatDataTransferValue ( bytes : number , l10nId : string ) {
513- if ( ! this . _co2 ) {
514- this . _co2 = new co2 ( { model : 'swd' } ) ;
515- }
516- // By default, when estimating emissions per byte, co2.js takes into account
517- // emissions for the user device, the data center and the network.
518- // Because we already have power tracks showing the power use and estimated
519- // emissions of the device, set the 'device' grid intensity to 0 to avoid
520- // double counting.
521- const co2eq = this . _co2 . perByteTrace ( bytes , false , {
522- gridIntensity : { device : 0 } ,
523- } ) ;
524- const carbonValue = formatNumber (
525- typeof co2eq . co2 === 'number' ? co2eq . co2 : co2eq . co2 . total
526- ) ;
527- const value = formatBytes ( bytes ) ;
528- return (
529- < Localized
530- id = { l10nId }
531- vars = { { value, carbonValue } }
532- attrs = { { label : true } }
533- >
534- < TooltipDetail label = "" > { value } </ TooltipDetail >
535- </ Localized >
536- ) ;
537- }
538-
539491 _renderTooltip ( counterIndex : number ) : React . ReactNode {
540492 const {
541- accumulatedSamples,
542493 counter,
543494 rangeStart,
544495 rangeEnd,
545- interval ,
496+ accumulatedSamples ,
546497 maxCounterSampleCountPerMs,
547- previewSelection,
548498 } = this . props ;
549- const { display } = counter ;
550499 const { mouseX, mouseY } = this . state ;
551500 const { samples } = counter ;
552501
@@ -563,182 +512,15 @@ class TrackCounterGraphImpl extends React.PureComponent<Props, State> {
563512 return null ;
564513 }
565514
566- const { category, name } = counter ;
567-
568- // Power tooltip — delegate to the dedicated component.
569- if ( category === 'power' ) {
570- return (
571- < Tooltip mouseX = { mouseX } mouseY = { mouseY } >
572- < TooltipTrackPower
573- counter = { counter }
574- counterSampleIndex = { counterIndex }
575- />
576- </ Tooltip >
577- ) ;
578- }
579-
580- // Process CPU tooltip.
581- if ( category === 'CPU' && name === 'processCPU' ) {
582- const cpuUsage = samples . count [ counterIndex ] ;
583- const sampleTimeDeltaInMs =
584- counterIndex === 0
585- ? interval
586- : samples . time [ counterIndex ] - samples . time [ counterIndex - 1 ] ;
587- const cpuRatio =
588- cpuUsage / sampleTimeDeltaInMs / maxCounterSampleCountPerMs ;
589- return (
590- < Tooltip mouseX = { mouseX } mouseY = { mouseY } >
591- < div className = "timelineTrackCounterTooltip" >
592- < div className = "timelineTrackCounterTooltipLine" >
593- CPU:{ ' ' }
594- < span className = "timelineTrackCounterTooltipNumber" >
595- { formatPercent ( cpuRatio ) }
596- </ span >
597- </ div >
598- </ div >
599- </ Tooltip >
600- ) ;
601- }
602-
603- // Bandwidth tooltip — bytes with rate, CO2, and accumulated total.
604- if ( category === 'Bandwidth' ) {
605- const { minCount, countRange, accumulatedCounts } = accumulatedSamples ;
606- const bytes = accumulatedCounts [ counterIndex ] - minCount ;
607- const operations =
608- samples . number !== undefined ? samples . number [ counterIndex ] : null ;
609-
610- const sampleTimeDeltaInMs =
611- counterIndex === 0
612- ? interval
613- : samples . time [ counterIndex ] - samples . time [ counterIndex - 1 ] ;
614- const unitGraphCount = samples . count [ counterIndex ] / sampleTimeDeltaInMs ;
615-
616- let rangeTotal = 0 ;
617- if ( previewSelection ) {
618- const [ beginIndex , endIndex ] = getSampleIndexRangeForSelection (
619- samples ,
620- previewSelection . selectionStart ,
621- previewSelection . selectionEnd
622- ) ;
623-
624- for (
625- let counterSampleIndex = beginIndex ;
626- counterSampleIndex < endIndex ;
627- counterSampleIndex ++
628- ) {
629- rangeTotal += samples . count [ counterSampleIndex ] ;
630- }
631- }
632-
633- let ops ;
634- if ( operations !== null ) {
635- ops = formatNumber ( operations , 2 , 0 ) ;
636- }
637-
638- return (
639- < Tooltip mouseX = { mouseX } mouseY = { mouseY } >
640- < div className = "timelineTrackCounterTooltip" >
641- < TooltipDetails >
642- { this . _formatDataTransferValue (
643- unitGraphCount * 1000 /* ms -> s */ ,
644- 'TrackBandwidthGraph--speed'
645- ) }
646- { operations !== null ? (
647- < Localized
648- id = "TrackBandwidthGraph--read-write-operations-since-the-previous-sample"
649- vars = { { value : ops || '' } }
650- attrs = { { label : true } }
651- >
652- < TooltipDetail label = "" > { ops } </ TooltipDetail >
653- </ Localized >
654- ) : null }
655- < TooltipDetailSeparator />
656- { this . _formatDataTransferValue (
657- bytes ,
658- 'TrackBandwidthGraph--cumulative-bandwidth-at-this-time'
659- ) }
660- { this . _formatDataTransferValue (
661- countRange ,
662- 'TrackBandwidthGraph--total-bandwidth-in-graph'
663- ) }
664- { previewSelection
665- ? this . _formatDataTransferValue (
666- rangeTotal ,
667- 'TrackBandwidthGraph--total-bandwidth-in-range'
668- )
669- : null }
670- </ TooltipDetails >
671- </ div >
672- </ Tooltip >
673- ) ;
674- }
675-
676- // Memory tooltip — accumulated bytes with operations count.
677- if ( category === 'Memory' ) {
678- const { minCount, countRange, accumulatedCounts } = accumulatedSamples ;
679- const bytes = accumulatedCounts [ counterIndex ] - minCount ;
680- const operations =
681- samples . number !== undefined ? samples . number [ counterIndex ] : null ;
682- return (
683- < Tooltip mouseX = { mouseX } mouseY = { mouseY } >
684- < div className = "timelineTrackCounterTooltip" >
685- < div className = "timelineTrackCounterTooltipLine" >
686- < span className = "timelineTrackCounterTooltipNumber" >
687- { formatBytes ( bytes ) }
688- </ span >
689- < Localized id = "TrackMemoryGraph--relative-memory-at-this-time" >
690- relative memory at this time
691- </ Localized >
692- </ div >
693-
694- < div className = "timelineTrackCounterTooltipLine" >
695- < span className = "timelineTrackCounterTooltipNumber" >
696- { formatBytes ( countRange ) }
697- </ span >
698- < Localized id = "TrackMemoryGraph--memory-range-in-graph" >
699- memory range in graph
700- </ Localized >
701- </ div >
702- { operations !== null ? (
703- < div className = "timelineTrackCounterTooltipLine" >
704- < span className = "timelineTrackCounterTooltipNumber" >
705- { formatNumber ( operations , 2 , 0 ) }
706- </ span >
707- < Localized id = "TrackMemoryGraph--allocations-and-deallocations-since-the-previous-sample" >
708- allocations and deallocations since the previous sample
709- </ Localized >
710- </ div >
711- ) : null }
712- </ div >
713- </ Tooltip >
714- ) ;
715- }
716-
717- // Generic tooltip for unknown counter types - format the value based on
718- // the counter's unit.
719- const value = samples . count [ counterIndex ] ;
720- let formattedValue ;
721- if ( display . unit === 'bytes' ) {
722- formattedValue = formatBytes ( value ) ;
723- } else if ( display . unit === 'percent' ) {
724- formattedValue = formatPercent ( value ) ;
725- } else if ( display . unit ) {
726- // Bypasses i18n but this is hit only for unknown counters.
727- formattedValue = `${ formatNumber ( value ) } ${ display . unit } ` ;
728- } else {
729- formattedValue = formatNumber ( value ) ;
730- }
731515 return (
732- < Tooltip mouseX = { mouseX } mouseY = { mouseY } >
733- < div className = "timelineTrackCounterTooltip" >
734- < div className = "timelineTrackCounterTooltipLine" >
735- < span className = "timelineTrackCounterTooltipNumber" >
736- { formattedValue }
737- </ span >
738- { display . label || name }
739- </ div >
740- </ div >
741- </ Tooltip >
516+ < TrackCounterTooltip
517+ counter = { counter }
518+ counterIndex = { counterIndex }
519+ accumulatedSamples = { accumulatedSamples }
520+ maxCounterSampleCountPerMs = { maxCounterSampleCountPerMs }
521+ mouseX = { mouseX }
522+ mouseY = { mouseY }
523+ />
742524 ) ;
743525 }
744526
@@ -894,7 +676,6 @@ export const TrackCounterGraph = explicitConnect<
894676 interval : getProfileInterval ( state ) ,
895677 filteredThread : selectors . getFilteredThread ( state ) ,
896678 unfilteredSamplesRange : selectors . unfilteredSamplesRange ( state ) ,
897- previewSelection : getPreviewSelection ( state ) ,
898679 } ;
899680 } ,
900681 component : withSize ( TrackCounterGraphImpl ) ,
0 commit comments