]> www.infradead.org Git - users/willy/xarray.git/commitdiff
perf sched: Fix thread leaks in 'perf sched timehist'
authorNamhyung Kim <namhyung@kernel.org>
Thu, 3 Jul 2025 01:49:38 +0000 (18:49 -0700)
committerNamhyung Kim <namhyung@kernel.org>
Thu, 3 Jul 2025 18:33:18 +0000 (11:33 -0700)
Add missing thread__put() after machine__findnew_thread() or
timehist_get_thread().  Also idle threads' last_thread should be
refcounted properly.

Fixes: 699b5b920db04a6f ("perf sched timehist: Save callchain when entering idle")
Reviewed-by: Ian Rogers <irogers@google.com>
Tested-by: Ian Rogers <irogers@google.com>
Link: https://lore.kernel.org/r/20250703014942.1369397-5-namhyung@kernel.org
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
tools/perf/builtin-sched.c

index b73989fb6acef8d6d5bdfc88ec879693ec37897e..83b5a85a91b7ffbd96e951caf0554f952dc24039 100644 (file)
@@ -2313,8 +2313,10 @@ static void save_task_callchain(struct perf_sched *sched,
                return;
        }
 
-       if (!sched->show_callchain || sample->callchain == NULL)
+       if (!sched->show_callchain || sample->callchain == NULL) {
+               thread__put(thread);
                return;
+       }
 
        cursor = get_tls_callchain_cursor();
 
@@ -2323,10 +2325,12 @@ static void save_task_callchain(struct perf_sched *sched,
                if (verbose > 0)
                        pr_err("Failed to resolve callchain. Skipping\n");
 
+               thread__put(thread);
                return;
        }
 
        callchain_cursor_commit(cursor);
+       thread__put(thread);
 
        while (true) {
                struct callchain_cursor_node *node;
@@ -2403,8 +2407,17 @@ static void free_idle_threads(void)
                return;
 
        for (i = 0; i < idle_max_cpu; ++i) {
-               if ((idle_threads[i]))
-                       thread__delete(idle_threads[i]);
+               struct thread *idle = idle_threads[i];
+
+               if (idle) {
+                       struct idle_thread_runtime *itr;
+
+                       itr = thread__priv(idle);
+                       if (itr)
+                               thread__put(itr->last_thread);
+
+                       thread__delete(idle);
+               }
        }
 
        free(idle_threads);
@@ -2441,7 +2454,7 @@ static struct thread *get_idle_thread(int cpu)
                }
        }
 
-       return idle_threads[cpu];
+       return thread__get(idle_threads[cpu]);
 }
 
 static void save_idle_callchain(struct perf_sched *sched,
@@ -2496,7 +2509,8 @@ static struct thread *timehist_get_thread(struct perf_sched *sched,
                        if (itr == NULL)
                                return NULL;
 
-                       itr->last_thread = thread;
+                       thread__put(itr->last_thread);
+                       itr->last_thread = thread__get(thread);
 
                        /* copy task callchain when entering to idle */
                        if (evsel__intval(evsel, sample, "next_pid") == 0)
@@ -2567,6 +2581,7 @@ static void timehist_print_wakeup_event(struct perf_sched *sched,
        /* show wakeup unless both awakee and awaker are filtered */
        if (timehist_skip_sample(sched, thread, evsel, sample) &&
            timehist_skip_sample(sched, awakened, evsel, sample)) {
+               thread__put(thread);
                return;
        }
 
@@ -2583,6 +2598,8 @@ static void timehist_print_wakeup_event(struct perf_sched *sched,
        printf("awakened: %s", timehist_get_commstr(awakened));
 
        printf("\n");
+
+       thread__put(thread);
 }
 
 static int timehist_sched_wakeup_ignore(const struct perf_tool *tool __maybe_unused,
@@ -2611,8 +2628,10 @@ static int timehist_sched_wakeup_event(const struct perf_tool *tool,
                return -1;
 
        tr = thread__get_runtime(thread);
-       if (tr == NULL)
+       if (tr == NULL) {
+               thread__put(thread);
                return -1;
+       }
 
        if (tr->ready_to_run == 0)
                tr->ready_to_run = sample->time;
@@ -2622,6 +2641,7 @@ static int timehist_sched_wakeup_event(const struct perf_tool *tool,
            !perf_time__skip_sample(&sched->ptime, sample->time))
                timehist_print_wakeup_event(sched, evsel, sample, machine, thread);
 
+       thread__put(thread);
        return 0;
 }
 
@@ -2649,6 +2669,7 @@ static void timehist_print_migration_event(struct perf_sched *sched,
 
        if (timehist_skip_sample(sched, thread, evsel, sample) &&
            timehist_skip_sample(sched, migrated, evsel, sample)) {
+               thread__put(thread);
                return;
        }
 
@@ -2676,6 +2697,7 @@ static void timehist_print_migration_event(struct perf_sched *sched,
        printf(" cpu %d => %d", ocpu, dcpu);
 
        printf("\n");
+       thread__put(thread);
 }
 
 static int timehist_migrate_task_event(const struct perf_tool *tool,
@@ -2695,8 +2717,10 @@ static int timehist_migrate_task_event(const struct perf_tool *tool,
                return -1;
 
        tr = thread__get_runtime(thread);
-       if (tr == NULL)
+       if (tr == NULL) {
+               thread__put(thread);
                return -1;
+       }
 
        tr->migrations++;
        tr->migrated = sample->time;
@@ -2706,6 +2730,7 @@ static int timehist_migrate_task_event(const struct perf_tool *tool,
                timehist_print_migration_event(sched, evsel, sample,
                                                        machine, thread);
        }
+       thread__put(thread);
 
        return 0;
 }
@@ -2728,10 +2753,10 @@ static void timehist_update_task_prio(struct evsel *evsel,
                return;
 
        tr = thread__get_runtime(thread);
-       if (tr == NULL)
-               return;
+       if (tr != NULL)
+               tr->prio = next_prio;
 
-       tr->prio = next_prio;
+       thread__put(thread);
 }
 
 static int timehist_sched_change_event(const struct perf_tool *tool,
@@ -2743,7 +2768,7 @@ static int timehist_sched_change_event(const struct perf_tool *tool,
        struct perf_sched *sched = container_of(tool, struct perf_sched, tool);
        struct perf_time_interval *ptime = &sched->ptime;
        struct addr_location al;
-       struct thread *thread;
+       struct thread *thread = NULL;
        struct thread_runtime *tr = NULL;
        u64 tprev, t = sample->time;
        int rc = 0;
@@ -2867,6 +2892,7 @@ out:
 
        evsel__save_time(evsel, sample->time, sample->cpu);
 
+       thread__put(thread);
        addr_location__exit(&al);
        return rc;
 }