@@ -375,6 +375,7 @@ enum event_type_t {
375
375
EVENT_TIME = 0x4 ,
376
376
/* see ctx_resched() for details */
377
377
EVENT_CPU = 0x8 ,
378
+ EVENT_CGROUP = 0x10 ,
378
379
EVENT_ALL = EVENT_FLEXIBLE | EVENT_PINNED ,
379
380
};
380
381
@@ -684,20 +685,26 @@ do { \
684
685
___p; \
685
686
})
686
687
687
- static void perf_ctx_disable (struct perf_event_context * ctx )
688
+ static void perf_ctx_disable (struct perf_event_context * ctx , bool cgroup )
688
689
{
689
690
struct perf_event_pmu_context * pmu_ctx ;
690
691
691
- list_for_each_entry (pmu_ctx , & ctx -> pmu_ctx_list , pmu_ctx_entry )
692
+ list_for_each_entry (pmu_ctx , & ctx -> pmu_ctx_list , pmu_ctx_entry ) {
693
+ if (cgroup && !pmu_ctx -> nr_cgroups )
694
+ continue ;
692
695
perf_pmu_disable (pmu_ctx -> pmu );
696
+ }
693
697
}
694
698
695
- static void perf_ctx_enable (struct perf_event_context * ctx )
699
+ static void perf_ctx_enable (struct perf_event_context * ctx , bool cgroup )
696
700
{
697
701
struct perf_event_pmu_context * pmu_ctx ;
698
702
699
- list_for_each_entry (pmu_ctx , & ctx -> pmu_ctx_list , pmu_ctx_entry )
703
+ list_for_each_entry (pmu_ctx , & ctx -> pmu_ctx_list , pmu_ctx_entry ) {
704
+ if (cgroup && !pmu_ctx -> nr_cgroups )
705
+ continue ;
700
706
perf_pmu_enable (pmu_ctx -> pmu );
707
+ }
701
708
}
702
709
703
710
static void ctx_sched_out (struct perf_event_context * ctx , enum event_type_t event_type );
@@ -856,9 +863,9 @@ static void perf_cgroup_switch(struct task_struct *task)
856
863
return ;
857
864
858
865
perf_ctx_lock (cpuctx , cpuctx -> task_ctx );
859
- perf_ctx_disable (& cpuctx -> ctx );
866
+ perf_ctx_disable (& cpuctx -> ctx , true );
860
867
861
- ctx_sched_out (& cpuctx -> ctx , EVENT_ALL );
868
+ ctx_sched_out (& cpuctx -> ctx , EVENT_ALL | EVENT_CGROUP );
862
869
/*
863
870
* must not be done before ctxswout due
864
871
* to update_cgrp_time_from_cpuctx() in
@@ -870,9 +877,9 @@ static void perf_cgroup_switch(struct task_struct *task)
870
877
* perf_cgroup_set_timestamp() in ctx_sched_in()
871
878
* to not have to pass task around
872
879
*/
873
- ctx_sched_in (& cpuctx -> ctx , EVENT_ALL );
880
+ ctx_sched_in (& cpuctx -> ctx , EVENT_ALL | EVENT_CGROUP );
874
881
875
- perf_ctx_enable (& cpuctx -> ctx );
882
+ perf_ctx_enable (& cpuctx -> ctx , true );
876
883
perf_ctx_unlock (cpuctx , cpuctx -> task_ctx );
877
884
}
878
885
@@ -965,6 +972,8 @@ perf_cgroup_event_enable(struct perf_event *event, struct perf_event_context *ct
965
972
if (!is_cgroup_event (event ))
966
973
return ;
967
974
975
+ event -> pmu_ctx -> nr_cgroups ++ ;
976
+
968
977
/*
969
978
* Because cgroup events are always per-cpu events,
970
979
* @ctx == &cpuctx->ctx.
@@ -985,6 +994,8 @@ perf_cgroup_event_disable(struct perf_event *event, struct perf_event_context *c
985
994
if (!is_cgroup_event (event ))
986
995
return ;
987
996
997
+ event -> pmu_ctx -> nr_cgroups -- ;
998
+
988
999
/*
989
1000
* Because cgroup events are always per-cpu events,
990
1001
* @ctx == &cpuctx->ctx.
@@ -2677,9 +2688,9 @@ static void ctx_resched(struct perf_cpu_context *cpuctx,
2677
2688
2678
2689
event_type &= EVENT_ALL ;
2679
2690
2680
- perf_ctx_disable (& cpuctx -> ctx );
2691
+ perf_ctx_disable (& cpuctx -> ctx , false );
2681
2692
if (task_ctx ) {
2682
- perf_ctx_disable (task_ctx );
2693
+ perf_ctx_disable (task_ctx , false );
2683
2694
task_ctx_sched_out (task_ctx , event_type );
2684
2695
}
2685
2696
@@ -2697,9 +2708,9 @@ static void ctx_resched(struct perf_cpu_context *cpuctx,
2697
2708
2698
2709
perf_event_sched_in (cpuctx , task_ctx );
2699
2710
2700
- perf_ctx_enable (& cpuctx -> ctx );
2711
+ perf_ctx_enable (& cpuctx -> ctx , false );
2701
2712
if (task_ctx )
2702
- perf_ctx_enable (task_ctx );
2713
+ perf_ctx_enable (task_ctx , false );
2703
2714
}
2704
2715
2705
2716
void perf_pmu_resched (struct pmu * pmu )
@@ -3244,6 +3255,9 @@ ctx_sched_out(struct perf_event_context *ctx, enum event_type_t event_type)
3244
3255
struct perf_cpu_context * cpuctx = this_cpu_ptr (& perf_cpu_context );
3245
3256
struct perf_event_pmu_context * pmu_ctx ;
3246
3257
int is_active = ctx -> is_active ;
3258
+ bool cgroup = event_type & EVENT_CGROUP ;
3259
+
3260
+ event_type &= ~EVENT_CGROUP ;
3247
3261
3248
3262
lockdep_assert_held (& ctx -> lock );
3249
3263
@@ -3290,8 +3304,11 @@ ctx_sched_out(struct perf_event_context *ctx, enum event_type_t event_type)
3290
3304
3291
3305
is_active ^= ctx -> is_active ; /* changed bits */
3292
3306
3293
- list_for_each_entry (pmu_ctx , & ctx -> pmu_ctx_list , pmu_ctx_entry )
3307
+ list_for_each_entry (pmu_ctx , & ctx -> pmu_ctx_list , pmu_ctx_entry ) {
3308
+ if (cgroup && !pmu_ctx -> nr_cgroups )
3309
+ continue ;
3294
3310
__pmu_ctx_sched_out (pmu_ctx , is_active );
3311
+ }
3295
3312
}
3296
3313
3297
3314
/*
@@ -3482,7 +3499,7 @@ perf_event_context_sched_out(struct task_struct *task, struct task_struct *next)
3482
3499
raw_spin_lock_nested (& next_ctx -> lock , SINGLE_DEPTH_NESTING );
3483
3500
if (context_equiv (ctx , next_ctx )) {
3484
3501
3485
- perf_ctx_disable (ctx );
3502
+ perf_ctx_disable (ctx , false );
3486
3503
3487
3504
/* PMIs are disabled; ctx->nr_pending is stable. */
3488
3505
if (local_read (& ctx -> nr_pending ) ||
@@ -3502,7 +3519,7 @@ perf_event_context_sched_out(struct task_struct *task, struct task_struct *next)
3502
3519
perf_ctx_sched_task_cb (ctx , false);
3503
3520
perf_event_swap_task_ctx_data (ctx , next_ctx );
3504
3521
3505
- perf_ctx_enable (ctx );
3522
+ perf_ctx_enable (ctx , false );
3506
3523
3507
3524
/*
3508
3525
* RCU_INIT_POINTER here is safe because we've not
@@ -3526,13 +3543,13 @@ perf_event_context_sched_out(struct task_struct *task, struct task_struct *next)
3526
3543
3527
3544
if (do_switch ) {
3528
3545
raw_spin_lock (& ctx -> lock );
3529
- perf_ctx_disable (ctx );
3546
+ perf_ctx_disable (ctx , false );
3530
3547
3531
3548
inside_switch :
3532
3549
perf_ctx_sched_task_cb (ctx , false);
3533
3550
task_ctx_sched_out (ctx , EVENT_ALL );
3534
3551
3535
- perf_ctx_enable (ctx );
3552
+ perf_ctx_enable (ctx , false );
3536
3553
raw_spin_unlock (& ctx -> lock );
3537
3554
}
3538
3555
}
@@ -3818,54 +3835,42 @@ static int merge_sched_in(struct perf_event *event, void *data)
3818
3835
return 0 ;
3819
3836
}
3820
3837
3821
- static void ctx_pinned_sched_in (struct perf_event_context * ctx , struct pmu * pmu )
3838
+ static void pmu_groups_sched_in (struct perf_event_context * ctx ,
3839
+ struct perf_event_groups * groups ,
3840
+ struct pmu * pmu )
3822
3841
{
3823
- struct perf_event_pmu_context * pmu_ctx ;
3824
3842
int can_add_hw = 1 ;
3825
-
3826
- if (pmu ) {
3827
- visit_groups_merge (ctx , & ctx -> pinned_groups ,
3828
- smp_processor_id (), pmu ,
3829
- merge_sched_in , & can_add_hw );
3830
- } else {
3831
- list_for_each_entry (pmu_ctx , & ctx -> pmu_ctx_list , pmu_ctx_entry ) {
3832
- can_add_hw = 1 ;
3833
- visit_groups_merge (ctx , & ctx -> pinned_groups ,
3834
- smp_processor_id (), pmu_ctx -> pmu ,
3835
- merge_sched_in , & can_add_hw );
3836
- }
3837
- }
3843
+ visit_groups_merge (ctx , groups , smp_processor_id (), pmu ,
3844
+ merge_sched_in , & can_add_hw );
3838
3845
}
3839
3846
3840
- static void ctx_flexible_sched_in (struct perf_event_context * ctx , struct pmu * pmu )
3847
+ static void ctx_groups_sched_in (struct perf_event_context * ctx ,
3848
+ struct perf_event_groups * groups ,
3849
+ bool cgroup )
3841
3850
{
3842
3851
struct perf_event_pmu_context * pmu_ctx ;
3843
- int can_add_hw = 1 ;
3844
3852
3845
- if (pmu ) {
3846
- visit_groups_merge (ctx , & ctx -> flexible_groups ,
3847
- smp_processor_id (), pmu ,
3848
- merge_sched_in , & can_add_hw );
3849
- } else {
3850
- list_for_each_entry (pmu_ctx , & ctx -> pmu_ctx_list , pmu_ctx_entry ) {
3851
- can_add_hw = 1 ;
3852
- visit_groups_merge (ctx , & ctx -> flexible_groups ,
3853
- smp_processor_id (), pmu_ctx -> pmu ,
3854
- merge_sched_in , & can_add_hw );
3855
- }
3853
+ list_for_each_entry (pmu_ctx , & ctx -> pmu_ctx_list , pmu_ctx_entry ) {
3854
+ if (cgroup && !pmu_ctx -> nr_cgroups )
3855
+ continue ;
3856
+ pmu_groups_sched_in (ctx , groups , pmu_ctx -> pmu );
3856
3857
}
3857
3858
}
3858
3859
3859
- static void __pmu_ctx_sched_in (struct perf_event_context * ctx , struct pmu * pmu )
3860
+ static void __pmu_ctx_sched_in (struct perf_event_context * ctx ,
3861
+ struct pmu * pmu )
3860
3862
{
3861
- ctx_flexible_sched_in (ctx , pmu );
3863
+ pmu_groups_sched_in (ctx , & ctx -> flexible_groups , pmu );
3862
3864
}
3863
3865
3864
3866
static void
3865
3867
ctx_sched_in (struct perf_event_context * ctx , enum event_type_t event_type )
3866
3868
{
3867
3869
struct perf_cpu_context * cpuctx = this_cpu_ptr (& perf_cpu_context );
3868
3870
int is_active = ctx -> is_active ;
3871
+ bool cgroup = event_type & EVENT_CGROUP ;
3872
+
3873
+ event_type &= ~EVENT_CGROUP ;
3869
3874
3870
3875
lockdep_assert_held (& ctx -> lock );
3871
3876
@@ -3898,11 +3903,11 @@ ctx_sched_in(struct perf_event_context *ctx, enum event_type_t event_type)
3898
3903
* in order to give them the best chance of going on.
3899
3904
*/
3900
3905
if (is_active & EVENT_PINNED )
3901
- ctx_pinned_sched_in (ctx , NULL );
3906
+ ctx_groups_sched_in (ctx , & ctx -> pinned_groups , cgroup );
3902
3907
3903
3908
/* Then walk through the lower prio flexible groups */
3904
3909
if (is_active & EVENT_FLEXIBLE )
3905
- ctx_flexible_sched_in (ctx , NULL );
3910
+ ctx_groups_sched_in (ctx , & ctx -> flexible_groups , cgroup );
3906
3911
}
3907
3912
3908
3913
static void perf_event_context_sched_in (struct task_struct * task )
@@ -3917,11 +3922,11 @@ static void perf_event_context_sched_in(struct task_struct *task)
3917
3922
3918
3923
if (cpuctx -> task_ctx == ctx ) {
3919
3924
perf_ctx_lock (cpuctx , ctx );
3920
- perf_ctx_disable (ctx );
3925
+ perf_ctx_disable (ctx , false );
3921
3926
3922
3927
perf_ctx_sched_task_cb (ctx , true);
3923
3928
3924
- perf_ctx_enable (ctx );
3929
+ perf_ctx_enable (ctx , false );
3925
3930
perf_ctx_unlock (cpuctx , ctx );
3926
3931
goto rcu_unlock ;
3927
3932
}
@@ -3934,7 +3939,7 @@ static void perf_event_context_sched_in(struct task_struct *task)
3934
3939
if (!ctx -> nr_events )
3935
3940
goto unlock ;
3936
3941
3937
- perf_ctx_disable (ctx );
3942
+ perf_ctx_disable (ctx , false );
3938
3943
/*
3939
3944
* We want to keep the following priority order:
3940
3945
* cpu pinned (that don't need to move), task pinned,
@@ -3944,7 +3949,7 @@ static void perf_event_context_sched_in(struct task_struct *task)
3944
3949
* events, no need to flip the cpuctx's events around.
3945
3950
*/
3946
3951
if (!RB_EMPTY_ROOT (& ctx -> pinned_groups .tree )) {
3947
- perf_ctx_disable (& cpuctx -> ctx );
3952
+ perf_ctx_disable (& cpuctx -> ctx , false );
3948
3953
ctx_sched_out (& cpuctx -> ctx , EVENT_FLEXIBLE );
3949
3954
}
3950
3955
@@ -3953,9 +3958,9 @@ static void perf_event_context_sched_in(struct task_struct *task)
3953
3958
perf_ctx_sched_task_cb (cpuctx -> task_ctx , true);
3954
3959
3955
3960
if (!RB_EMPTY_ROOT (& ctx -> pinned_groups .tree ))
3956
- perf_ctx_enable (& cpuctx -> ctx );
3961
+ perf_ctx_enable (& cpuctx -> ctx , false );
3957
3962
3958
- perf_ctx_enable (ctx );
3963
+ perf_ctx_enable (ctx , false );
3959
3964
3960
3965
unlock :
3961
3966
perf_ctx_unlock (cpuctx , ctx );
0 commit comments