@@ -568,53 +568,53 @@ _topdown_init_control_state(hwd_control_state_t *ctl)
568568 int metrics_fd = -1 ;
569569 void * slots_p , * metrics_p ;
570570
571- /* set up slots */
571+ // Set up slots
572572 memset (& slots , 0 , sizeof (slots ));
573573 slots .type = PERF_TYPE_RAW ;
574574 slots .size = sizeof (struct perf_event_attr );
575575 slots .config = 0x0400ull ;
576576 slots .exclude_kernel = 1 ;
577577
578- /* open slots */
578+ // Open slots
579579 slots_fd = perf_event_open (& slots , 0 , -1 , -1 , 0 );
580580 if (slots_fd < 0 )
581581 {
582582 retval = PAPI_ENOMEM ;
583583 goto fn_fail ;
584584 }
585585
586- /* memory mapping the fd to permit _rdpmc calls from userspace */
586+ // Memory mapping the fd to permit _rdpmc calls from userspace
587587 slots_p = mmap (0 , getpagesize (), PROT_READ , MAP_SHARED , slots_fd , 0 );
588588 if (slots_p == (void * ) -1L )
589589 {
590590 retval = PAPI_ENOMEM ;
591591 goto fn_fail ;
592592 }
593593
594- /* set up metrics */
594+ // Set up metrics
595595 memset (& metrics , 0 , sizeof (metrics ));
596596 metrics .type = PERF_TYPE_RAW ;
597597 metrics .size = sizeof (struct perf_event_attr );
598598 metrics .config = 0x8000 ;
599599 metrics .exclude_kernel = 1 ;
600600
601- /* open metrics with slots as the group leader */
601+ // Open metrics with slots as the group leader
602602 metrics_fd = perf_event_open (& metrics , 0 , -1 , slots_fd , 0 );
603603 if (metrics_fd < 0 )
604604 {
605605 retval = PAPI_ENOMEM ;
606606 goto fn_fail ;
607607 }
608608
609- /* memory mapping the fd to permit _rdpmc calls from userspace */
609+ // Memory mapping the fd to permit _rdpmc calls from userspace
610610 metrics_p = mmap (0 , getpagesize (), PROT_READ , MAP_SHARED , metrics_fd , 0 );
611611 if (metrics_p == (void * ) -1L )
612612 {
613613 retval = PAPI_ENOMEM ;
614614 goto fn_fail ;
615615 }
616616
617- /* we set up with no errors, so fill out the control state */
617+ // We set up with no errors, so fill out the control state
618618 control -> slots_fd = slots_fd ;
619619 control -> slots_p ;
620620 control -> metrics_fd = metrics_fd ;
@@ -624,7 +624,7 @@ _topdown_init_control_state(hwd_control_state_t *ctl)
624624 return retval ;
625625
626626fn_fail :
627- /* we need to close & free whatever we opened and allocated */
627+ // We need to close & free whatever we opened and allocated
628628 if (slots_p != NULL )
629629 munmap (slots_p , getpagesize ());
630630 if (metrics_p != NULL )
@@ -642,127 +642,176 @@ _topdown_update_control_state(hwd_control_state_t *ctl,
642642 int count ,
643643 hwd_context_t * ctx )
644644{
645- int i , index ;
646645 (void )ctx ;
647-
648646 _topdown_control_state_t * control = (_topdown_control_state_t * )ctl ;
649647
648+ int i ;
650649 for (i = 0 ; i < TOPDOWN_MAX_COUNTERS ; i ++ )
651650 {
652651 control -> being_measured [i ] = 0 ;
653652 }
654653
655654 for (i = 0 ; i < count ; i ++ )
656655 {
657- index = native [i ].ni_event & PAPI_NATIVE_AND_MASK ;
656+ int index = native [i ].ni_event & PAPI_NATIVE_AND_MASK ;
658657 native [i ].ni_position = topdown_native_events [index ].selector - 1 ;
659658 control -> being_measured [index ] = 1 ;
660659 }
661660
662661 return PAPI_OK ;
663662}
664663
665- static int
666- _topdown_start (hwd_context_t * ctx , hwd_control_state_t * ctl )
664+ /**@class _wrapper_perf_event_ioc_reset
665+ * @brief Reset the PERF_METRICS counter and slots to maintain precision
666+ * as perf the recommendation of section 21.3.9.3 of the IA-32
667+ * Architectures Software Developer's Manual. Resetting means we
668+ * do not need to record 'before' metrics/slot values, as they are
669+ * always effectively 0. Despite the reset meaning we don't need to
670+ * record the slots value at all, the SDM states that SLOTS and the
671+ * PERF_METRICS MSR should be reset together.
672+ */
673+ static
674+ int _wrapper_perf_event_ioc_reset (_topdown_control_state_t * control )
667675{
668- (void ) ctx ;
669- _topdown_control_state_t * control = (_topdown_control_state_t * )ctl ;
670-
671- /* reset the PERF_METRICS counter and slots to maintain precision */
672- /* as per the recommendation of section 21.3.9.3 of the IA-32
673- /* Architectures Software Developer’s Manual. Resetting means we do not */
674- /* need to record 'before' metrics/slots values, as they are always */
675- /* effectively 0. Despite the reset meaning we don't need to record */
676- /* the slots value at all, the SDM states that SLOTS and the PERF_METRICS */
677- /* MSR should be reset together, so we do that here. */
678-
679- /* these ioctl calls do not need to be protected by assert_affinity() */
680- ioctl (control -> slots_fd , PERF_EVENT_IOC_RESET , 0 );
681- ioctl (control -> metrics_fd , PERF_EVENT_IOC_RESET , 0 );
676+ // This ioctl call does not need to be protected by assert_affinity()
677+ int retval = ioctl (control -> slots_fd , PERF_EVENT_IOC_RESET , 0 );
678+ if (retval != 0 ) {
679+ SUBDBG ("Resetting control->slots_fd failed.\n" );
680+ return PAPI_ESYS ;
681+ }
682+
683+ // This ioctl call does not need to be protected by assert_affinity()
684+ retval = ioctl (control -> metrics_fd , PERF_EVENT_IOC_RESET , 0 );
685+ if (retval != 0 ) {
686+ SUBDBG ("Resetting control->metrics_fd failed.\n" );
687+ return PAPI_ESYS ;
688+ }
689+
690+ return PAPI_OK ;
691+ }
682692
683- return PAPI_OK ;
693+ /**@class _wrapper_perf_event_ioc_enable
694+ * @brief Enable the event's.
695+ *
696+ * NOTE: As control->slots_fd is the group leader for control->metrics_fd
697+ * you could use PERF_IOC_FLAG_GROUP in the ioctl argument to enable all events
698+ * in the group i.e. control->metrics_fd. However, from Linux 2.6.31 to Linux 3.4
699+ * PERF_IOC_FLAG_GROUP ioctl argument was broken.
700+ */
701+ static
702+ int _wrapper_perf_event_ioc_enable (_topdown_control_state_t * control )
703+ {
704+ int retval = ioctl (control -> slots_fd , PERF_EVENT_IOC_ENABLE , 0 );
705+ if (retval != PAPI_OK ) {
706+ SUBDBG ("Enabling control->slots_fd failed.\n" );
707+ return retval ;
708+ }
709+
710+ retval = ioctl (control -> metrics_fd , PERF_EVENT_IOC_ENABLE , 0 );
711+ if (retval != PAPI_OK ) {
712+ SUBDBG ("Enabling control->metrics_fd failed.\n" );
713+ return retval ;
714+ }
715+
716+ return PAPI_OK ;
684717}
685718
686719static int
687- _topdown_stop (hwd_context_t * ctx , hwd_control_state_t * ctl )
720+ _topdown_start (hwd_context_t * ctx , hwd_control_state_t * ctl )
688721{
689- _topdown_context_t * context = ( _topdown_context_t * )ctx ;
722+ ( void )ctx ;
690723 _topdown_control_state_t * control = (_topdown_control_state_t * )ctl ;
691- unsigned long long metrics_after ;
692-
693- int i , retval ;
694- double ma , mb , perc ;
695-
696- retval = PAPI_OK ;
697-
698- metrics_after = read_metrics ();
699724
700- /* extract the values */
701- for (i = 0 ; i < TOPDOWN_MAX_COUNTERS ; i ++ )
702- {
703- if (control -> being_measured [i ])
704- {
705- /* handle case where the metric is not derived */
706- if (topdown_native_events [i ].metric_idx >= 0 )
707- {
708- perc = extract_metric (topdown_native_events [i ].metric_idx ,
709- metrics_after ) * 100.0 ;
710- }
711- else /* handle case where the metric is derived */
712- {
713- /* metric perc = parent perc - sibling perc */
714- perc = extract_metric (
715- topdown_native_events [i ].derived_parent_idx ,
716- metrics_after ) * 100.0
717- - extract_metric (
718- topdown_native_events [i ].derived_sibling_idx ,
719- metrics_after ) * 100.0 ;
720- }
725+ // Reset counters to maintain precision.
726+ int retval = _wrapper_perf_event_ioc_reset (control );
727+ if (retval != PAPI_OK ) {
728+ return retval ;
729+ }
721730
722- /* sometimes the percentage will be a very small negative value */
723- /* instead of 0 due to floating point error. tidy that up: */
724- if (perc < 0.0 ) {
725- perc = 0.0 ;
726- }
727-
728- /* store the raw bits of the double into the counter value */
729- control -> count [i ] = * (long long * )& perc ;
730- }
731+ retval = _wrapper_perf_event_ioc_enable (control );
732+ if (retval != PAPI_OK ) {
733+ return retval ;
731734 }
732735
733- fn_exit :
734- /* free & close everything in the control state */
735- munmap (control -> slots_p , getpagesize ());
736- control -> slots_p = NULL ;
737- munmap (control -> metrics_p , getpagesize ());
738- control -> metrics_p = NULL ;
739- close (control -> slots_fd );
740- control -> slots_fd = -1 ;
741- close (control -> metrics_fd );
742- control -> metrics_fd = -1 ;
743-
744- return retval ;
736+ return PAPI_OK ;
745737}
746738
747739static int
748740_topdown_read (hwd_context_t * ctx , hwd_control_state_t * ctl ,
749- long long * * events , int flags )
741+ long long * * events , int flags )
750742{
751- (void )flags ;
743+ (void )flags ;
744+ (void )ctx ;
745+ _topdown_control_state_t * control = (_topdown_control_state_t * )ctl ;
746+
747+ // Extract the values
748+ unsigned long long metrics_after = read_metrics ();
749+ int i ;
750+ for (i = 0 ; i < TOPDOWN_MAX_COUNTERS ; i ++ )
751+ {
752+ if (control -> being_measured [i ])
753+ {
754+ double perc ;
755+ // Handle case where the metric is not derived
756+ if (topdown_native_events [i ].metric_idx >= 0 )
757+ {
758+ perc = extract_metric (topdown_native_events [i ].metric_idx ,
759+ metrics_after ) * 100.0 ;
760+ }
761+ else // Handle case where the metric is derived
762+ {
763+ // Metric perc = parent perc - sibling perc
764+ perc = extract_metric (
765+ topdown_native_events [i ].derived_parent_idx ,
766+ metrics_after ) * 100.0
767+ - extract_metric (
768+ topdown_native_events [i ].derived_sibling_idx ,
769+ metrics_after ) * 100.0 ;
770+ }
771+
772+ // Sometimes the percentage will be a very small negative value
773+ // instead of 0 due to floating point error. tidy that up:
774+ if (perc < 0.0 ) {
775+ perc = 0.0 ;
776+ }
777+
778+ // Store the raw bits of the double into the counter value
779+ control -> count [i ] = * (long long * )& perc ;
780+ }
781+ }
782+ // Pass back a pointer to our results
783+ * events = control -> count ;
784+
785+ return PAPI_OK ;
786+ }
752787
753- _topdown_stop (ctx , ctl );
788+ static int
789+ _topdown_reset (hwd_context_t * ctx , hwd_control_state_t * ctl )
790+ {
791+ (void )ctx ;
792+ _topdown_control_state_t * control = (_topdown_control_state_t * )ctl ;
754793
755- /* Pass back a pointer to our results */
756- * events = ((_topdown_control_state_t * )ctl )-> count ;
794+ int retval = _wrapper_perf_event_ioc_reset (control );
795+ if (retval != PAPI_OK ) {
796+ return retval ;
797+ }
757798
758- return PAPI_OK ;
799+ return PAPI_OK ;
759800}
760801
761802static int
762- _topdown_reset (hwd_context_t * ctx , hwd_control_state_t * ctl )
803+ _topdown_stop (hwd_context_t * ctx , hwd_control_state_t * ctl )
763804{
764- ( void ) ctx ;
765- ( void ) ctl ;
805+ (void )ctx ;
806+ _topdown_control_state_t * control = (_topdown_control_state_t * )ctl ;
807+
808+ // slots_fd is defined as the group leader in _topdown_init_control_state;
809+ // therefore, disabling slots_fd will disable the entire group.
810+ int retval = ioctl (control -> slots_fd , PERF_EVENT_IOC_DISABLE , 0 );
811+ if (retval != 0 ) {
812+ SUBDBG ("Disabling the entire event group failed.\n" );
813+ return PAPI_ESYS ;
814+ }
766815
767816 return PAPI_OK ;
768817}
0 commit comments