LCOV - code coverage report
Current view: top level - kernel/trace - trace_sched_wakeup.c (source / functions) Hit Total Coverage
Test: Real Lines: 7 271 2.6 %
Date: 2020-10-17 15:46:16 Functions: 0 32 0.0 %
Legend: Neither, QEMU, Real, Both Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0
       2                 :            : /*
       3                 :            :  * trace task wakeup timings
       4                 :            :  *
       5                 :            :  * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com>
       6                 :            :  * Copyright (C) 2008 Ingo Molnar <mingo@redhat.com>
       7                 :            :  *
       8                 :            :  * Based on code from the latency_tracer, that is:
       9                 :            :  *
      10                 :            :  *  Copyright (C) 2004-2006 Ingo Molnar
      11                 :            :  *  Copyright (C) 2004 Nadia Yvette Chambers
      12                 :            :  */
      13                 :            : #include <linux/module.h>
      14                 :            : #include <linux/kallsyms.h>
      15                 :            : #include <linux/uaccess.h>
      16                 :            : #include <linux/ftrace.h>
      17                 :            : #include <linux/sched/rt.h>
      18                 :            : #include <linux/sched/deadline.h>
      19                 :            : #include <trace/events/sched.h>
      20                 :            : #include "trace.h"
      21                 :            : 
      22                 :            : static struct trace_array       *wakeup_trace;
      23                 :            : static int __read_mostly        tracer_enabled;
      24                 :            : 
      25                 :            : static struct task_struct       *wakeup_task;
      26                 :            : static int                      wakeup_cpu;
      27                 :            : static int                      wakeup_current_cpu;
      28                 :            : static unsigned                 wakeup_prio = -1;
      29                 :            : static int                      wakeup_rt;
      30                 :            : static int                      wakeup_dl;
      31                 :            : static int                      tracing_dl = 0;
      32                 :            : 
      33                 :            : static arch_spinlock_t wakeup_lock =
      34                 :            :         (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED;
      35                 :            : 
      36                 :            : static void wakeup_reset(struct trace_array *tr);
      37                 :            : static void __wakeup_reset(struct trace_array *tr);
      38                 :            : static int start_func_tracer(struct trace_array *tr, int graph);
      39                 :            : static void stop_func_tracer(struct trace_array *tr, int graph);
      40                 :            : 
      41                 :            : static int save_flags;
      42                 :            : 
      43                 :            : #ifdef CONFIG_FUNCTION_GRAPH_TRACER
      44                 :            : # define is_graph(tr) ((tr)->trace_flags & TRACE_ITER_DISPLAY_GRAPH)
      45                 :            : #else
      46                 :            : # define is_graph(tr) false
      47                 :            : #endif
      48                 :            : 
      49                 :            : #ifdef CONFIG_FUNCTION_TRACER
      50                 :            : 
      51                 :            : static bool function_enabled;
      52                 :            : 
      53                 :            : /*
      54                 :            :  * Prologue for the wakeup function tracers.
      55                 :            :  *
      56                 :            :  * Returns 1 if it is OK to continue, and preemption
      57                 :            :  *            is disabled and data->disabled is incremented.
      58                 :            :  *         0 if the trace is to be ignored, and preemption
      59                 :            :  *            is not disabled and data->disabled is
      60                 :            :  *            kept the same.
      61                 :            :  *
      62                 :            :  * Note, this function is also used outside this ifdef but
      63                 :            :  *  inside the #ifdef of the function graph tracer below.
      64                 :            :  *  This is OK, since the function graph tracer is
      65                 :            :  *  dependent on the function tracer.
      66                 :            :  */
      67                 :            : static int
      68                 :          0 : func_prolog_preempt_disable(struct trace_array *tr,
      69                 :            :                             struct trace_array_cpu **data,
      70                 :            :                             int *pc)
      71                 :            : {
      72                 :            :         long disabled;
      73                 :            :         int cpu;
      74                 :            : 
      75                 :          0 :         if (likely(!wakeup_task))
      76                 :            :                 return 0;
      77                 :            : 
      78                 :          0 :         *pc = preempt_count();
      79                 :          0 :         preempt_disable_notrace();
      80                 :            : 
      81                 :          0 :         cpu = raw_smp_processor_id();
      82                 :          0 :         if (cpu != wakeup_current_cpu)
      83                 :            :                 goto out_enable;
      84                 :            : 
      85                 :          0 :         *data = per_cpu_ptr(tr->trace_buffer.data, cpu);
      86                 :          0 :         disabled = atomic_inc_return(&(*data)->disabled);
      87                 :          0 :         if (unlikely(disabled != 1))
      88                 :            :                 goto out;
      89                 :            : 
      90                 :            :         return 1;
      91                 :            : 
      92                 :            : out:
      93                 :          0 :         atomic_dec(&(*data)->disabled);
      94                 :            : 
      95                 :            : out_enable:
      96                 :          0 :         preempt_enable_notrace();
      97                 :          0 :         return 0;
      98                 :            : }
      99                 :            : 
     100                 :            : #ifdef CONFIG_FUNCTION_GRAPH_TRACER
     101                 :            : 
     102                 :          0 : static int wakeup_display_graph(struct trace_array *tr, int set)
     103                 :            : {
     104                 :          0 :         if (!(is_graph(tr) ^ set))
     105                 :            :                 return 0;
     106                 :            : 
     107                 :          0 :         stop_func_tracer(tr, !set);
     108                 :            : 
     109                 :          0 :         wakeup_reset(wakeup_trace);
     110                 :          0 :         tr->max_latency = 0;
     111                 :            : 
     112                 :          0 :         return start_func_tracer(tr, set);
     113                 :            : }
     114                 :            : 
     115                 :          0 : static int wakeup_graph_entry(struct ftrace_graph_ent *trace)
     116                 :            : {
     117                 :          0 :         struct trace_array *tr = wakeup_trace;
     118                 :            :         struct trace_array_cpu *data;
     119                 :            :         unsigned long flags;
     120                 :            :         int pc, ret = 0;
     121                 :            : 
     122                 :          0 :         if (ftrace_graph_ignore_func(trace))
     123                 :            :                 return 0;
     124                 :            :         /*
     125                 :            :          * Do not trace a function if it's filtered by set_graph_notrace.
     126                 :            :          * Make the index of ret stack negative to indicate that it should
     127                 :            :          * ignore further functions.  But it needs its own ret stack entry
     128                 :            :          * to recover the original index in order to continue tracing after
     129                 :            :          * returning from the function.
     130                 :            :          */
     131                 :          0 :         if (ftrace_graph_notrace_addr(trace->func))
     132                 :            :                 return 1;
     133                 :            : 
     134                 :          0 :         if (!func_prolog_preempt_disable(tr, &data, &pc))
     135                 :            :                 return 0;
     136                 :            : 
     137                 :            :         local_save_flags(flags);
     138                 :          0 :         ret = __trace_graph_entry(tr, trace, flags, pc);
     139                 :          0 :         atomic_dec(&data->disabled);
     140                 :          0 :         preempt_enable_notrace();
     141                 :            : 
     142                 :          0 :         return ret;
     143                 :            : }
     144                 :            : 
     145                 :          0 : static void wakeup_graph_return(struct ftrace_graph_ret *trace)
     146                 :            : {
     147                 :          0 :         struct trace_array *tr = wakeup_trace;
     148                 :            :         struct trace_array_cpu *data;
     149                 :            :         unsigned long flags;
     150                 :            :         int pc;
     151                 :            : 
     152                 :          0 :         ftrace_graph_addr_finish(trace);
     153                 :            : 
     154                 :          0 :         if (!func_prolog_preempt_disable(tr, &data, &pc))
     155                 :            :                 return;
     156                 :            : 
     157                 :            :         local_save_flags(flags);
     158                 :          0 :         __trace_graph_return(tr, trace, flags, pc);
     159                 :          0 :         atomic_dec(&data->disabled);
     160                 :            : 
     161                 :          0 :         preempt_enable_notrace();
     162                 :          0 :         return;
     163                 :            : }
     164                 :            : 
     165                 :            : static struct fgraph_ops fgraph_wakeup_ops = {
     166                 :            :         .entryfunc = &wakeup_graph_entry,
     167                 :            :         .retfunc = &wakeup_graph_return,
     168                 :            : };
     169                 :            : 
     170                 :          0 : static void wakeup_trace_open(struct trace_iterator *iter)
     171                 :            : {
     172                 :          0 :         if (is_graph(iter->tr))
     173                 :          0 :                 graph_trace_open(iter);
     174                 :          0 : }
     175                 :            : 
     176                 :          0 : static void wakeup_trace_close(struct trace_iterator *iter)
     177                 :            : {
     178                 :          0 :         if (iter->private)
     179                 :          0 :                 graph_trace_close(iter);
     180                 :          0 : }
     181                 :            : 
     182                 :            : #define GRAPH_TRACER_FLAGS (TRACE_GRAPH_PRINT_PROC | \
     183                 :            :                             TRACE_GRAPH_PRINT_CPU |  \
     184                 :            :                             TRACE_GRAPH_PRINT_REL_TIME | \
     185                 :            :                             TRACE_GRAPH_PRINT_DURATION | \
     186                 :            :                             TRACE_GRAPH_PRINT_OVERHEAD | \
     187                 :            :                             TRACE_GRAPH_PRINT_IRQS)
     188                 :            : 
     189                 :          0 : static enum print_line_t wakeup_print_line(struct trace_iterator *iter)
     190                 :            : {
     191                 :            :         /*
     192                 :            :          * In graph mode call the graph tracer output function,
     193                 :            :          * otherwise go with the TRACE_FN event handler
     194                 :            :          */
     195                 :          0 :         if (is_graph(iter->tr))
     196                 :          0 :                 return print_graph_function_flags(iter, GRAPH_TRACER_FLAGS);
     197                 :            : 
     198                 :            :         return TRACE_TYPE_UNHANDLED;
     199                 :            : }
     200                 :            : 
     201                 :          0 : static void wakeup_print_header(struct seq_file *s)
     202                 :            : {
     203                 :          0 :         if (is_graph(wakeup_trace))
     204                 :          0 :                 print_graph_headers_flags(s, GRAPH_TRACER_FLAGS);
     205                 :            :         else
     206                 :          0 :                 trace_default_header(s);
     207                 :          0 : }
     208                 :            : #endif /* else CONFIG_FUNCTION_GRAPH_TRACER */
     209                 :            : 
     210                 :            : /*
     211                 :            :  * wakeup uses its own tracer function to keep the overhead down:
     212                 :            :  */
     213                 :            : static void
     214                 :          0 : wakeup_tracer_call(unsigned long ip, unsigned long parent_ip,
     215                 :            :                    struct ftrace_ops *op, struct pt_regs *pt_regs)
     216                 :            : {
     217                 :          0 :         struct trace_array *tr = wakeup_trace;
     218                 :            :         struct trace_array_cpu *data;
     219                 :            :         unsigned long flags;
     220                 :            :         int pc;
     221                 :            : 
     222                 :          0 :         if (!func_prolog_preempt_disable(tr, &data, &pc))
     223                 :          0 :                 return;
     224                 :            : 
     225                 :          0 :         local_irq_save(flags);
     226                 :          0 :         trace_function(tr, ip, parent_ip, flags, pc);
     227                 :          0 :         local_irq_restore(flags);
     228                 :            : 
     229                 :          0 :         atomic_dec(&data->disabled);
     230                 :          0 :         preempt_enable_notrace();
     231                 :            : }
     232                 :            : 
     233                 :          0 : static int register_wakeup_function(struct trace_array *tr, int graph, int set)
     234                 :            : {
     235                 :            :         int ret;
     236                 :            : 
     237                 :            :         /* 'set' is set if TRACE_ITER_FUNCTION is about to be set */
     238                 :          0 :         if (function_enabled || (!set && !(tr->trace_flags & TRACE_ITER_FUNCTION)))
     239                 :            :                 return 0;
     240                 :            : 
     241                 :          0 :         if (graph)
     242                 :          0 :                 ret = register_ftrace_graph(&fgraph_wakeup_ops);
     243                 :            :         else
     244                 :          0 :                 ret = register_ftrace_function(tr->ops);
     245                 :            : 
     246                 :          0 :         if (!ret)
     247                 :          0 :                 function_enabled = true;
     248                 :            : 
     249                 :          0 :         return ret;
     250                 :            : }
     251                 :            : 
     252                 :          0 : static void unregister_wakeup_function(struct trace_array *tr, int graph)
     253                 :            : {
     254                 :          0 :         if (!function_enabled)
     255                 :          0 :                 return;
     256                 :            : 
     257                 :          0 :         if (graph)
     258                 :          0 :                 unregister_ftrace_graph(&fgraph_wakeup_ops);
     259                 :            :         else
     260                 :          0 :                 unregister_ftrace_function(tr->ops);
     261                 :            : 
     262                 :          0 :         function_enabled = false;
     263                 :            : }
     264                 :            : 
     265                 :          0 : static int wakeup_function_set(struct trace_array *tr, u32 mask, int set)
     266                 :            : {
     267                 :          0 :         if (!(mask & TRACE_ITER_FUNCTION))
     268                 :            :                 return 0;
     269                 :            : 
     270                 :          0 :         if (set)
     271                 :          0 :                 register_wakeup_function(tr, is_graph(tr), 1);
     272                 :            :         else
     273                 :          0 :                 unregister_wakeup_function(tr, is_graph(tr));
     274                 :            :         return 1;
     275                 :            : }
     276                 :            : #else /* CONFIG_FUNCTION_TRACER */
     277                 :            : static int register_wakeup_function(struct trace_array *tr, int graph, int set)
     278                 :            : {
     279                 :            :         return 0;
     280                 :            : }
     281                 :            : static void unregister_wakeup_function(struct trace_array *tr, int graph) { }
     282                 :            : static int wakeup_function_set(struct trace_array *tr, u32 mask, int set)
     283                 :            : {
     284                 :            :         return 0;
     285                 :            : }
     286                 :            : #endif /* else CONFIG_FUNCTION_TRACER */
     287                 :            : 
     288                 :            : #ifndef CONFIG_FUNCTION_GRAPH_TRACER
     289                 :            : static enum print_line_t wakeup_print_line(struct trace_iterator *iter)
     290                 :            : {
     291                 :            :         return TRACE_TYPE_UNHANDLED;
     292                 :            : }
     293                 :            : 
     294                 :            : static void wakeup_trace_open(struct trace_iterator *iter) { }
     295                 :            : static void wakeup_trace_close(struct trace_iterator *iter) { }
     296                 :            : 
     297                 :            : static void wakeup_print_header(struct seq_file *s)
     298                 :            : {
     299                 :            :         trace_default_header(s);
     300                 :            : }
     301                 :            : #endif /* !CONFIG_FUNCTION_GRAPH_TRACER */
     302                 :            : 
     303                 :            : static void
     304                 :          0 : __trace_function(struct trace_array *tr,
     305                 :            :                  unsigned long ip, unsigned long parent_ip,
     306                 :            :                  unsigned long flags, int pc)
     307                 :            : {
     308                 :          0 :         if (is_graph(tr))
     309                 :          0 :                 trace_graph_function(tr, ip, parent_ip, flags, pc);
     310                 :            :         else
     311                 :          0 :                 trace_function(tr, ip, parent_ip, flags, pc);
     312                 :          0 : }
     313                 :            : 
     314                 :          0 : static int wakeup_flag_changed(struct trace_array *tr, u32 mask, int set)
     315                 :            : {
     316                 :          0 :         struct tracer *tracer = tr->current_trace;
     317                 :            : 
     318                 :          0 :         if (wakeup_function_set(tr, mask, set))
     319                 :            :                 return 0;
     320                 :            : 
     321                 :            : #ifdef CONFIG_FUNCTION_GRAPH_TRACER
     322                 :          0 :         if (mask & TRACE_ITER_DISPLAY_GRAPH)
     323                 :          0 :                 return wakeup_display_graph(tr, set);
     324                 :            : #endif
     325                 :            : 
     326                 :          0 :         return trace_keep_overwrite(tracer, mask, set);
     327                 :            : }
     328                 :            : 
     329                 :          0 : static int start_func_tracer(struct trace_array *tr, int graph)
     330                 :            : {
     331                 :            :         int ret;
     332                 :            : 
     333                 :          0 :         ret = register_wakeup_function(tr, graph, 0);
     334                 :            : 
     335                 :          0 :         if (!ret && tracing_is_enabled())
     336                 :          0 :                 tracer_enabled = 1;
     337                 :            :         else
     338                 :          0 :                 tracer_enabled = 0;
     339                 :            : 
     340                 :          0 :         return ret;
     341                 :            : }
     342                 :            : 
     343                 :            : static void stop_func_tracer(struct trace_array *tr, int graph)
     344                 :            : {
     345                 :          0 :         tracer_enabled = 0;
     346                 :            : 
     347                 :          0 :         unregister_wakeup_function(tr, graph);
     348                 :            : }
     349                 :            : 
     350                 :            : /*
     351                 :            :  * Should this new latency be reported/recorded?
     352                 :            :  */
     353                 :            : static bool report_latency(struct trace_array *tr, u64 delta)
     354                 :            : {
     355                 :          0 :         if (tracing_thresh) {
     356                 :          0 :                 if (delta < tracing_thresh)
     357                 :            :                         return false;
     358                 :            :         } else {
     359                 :          0 :                 if (delta <= tr->max_latency)
     360                 :            :                         return false;
     361                 :            :         }
     362                 :            :         return true;
     363                 :            : }
     364                 :            : 
     365                 :            : static void
     366                 :          0 : probe_wakeup_migrate_task(void *ignore, struct task_struct *task, int cpu)
     367                 :            : {
     368                 :          0 :         if (task != wakeup_task)
     369                 :          0 :                 return;
     370                 :            : 
     371                 :          0 :         wakeup_current_cpu = cpu;
     372                 :            : }
     373                 :            : 
     374                 :            : static void
     375                 :          0 : tracing_sched_switch_trace(struct trace_array *tr,
     376                 :            :                            struct task_struct *prev,
     377                 :            :                            struct task_struct *next,
     378                 :            :                            unsigned long flags, int pc)
     379                 :            : {
     380                 :            :         struct trace_event_call *call = &event_context_switch;
     381                 :          0 :         struct ring_buffer *buffer = tr->trace_buffer.buffer;
     382                 :            :         struct ring_buffer_event *event;
     383                 :            :         struct ctx_switch_entry *entry;
     384                 :            : 
     385                 :          0 :         event = trace_buffer_lock_reserve(buffer, TRACE_CTX,
     386                 :            :                                           sizeof(*entry), flags, pc);
     387                 :          0 :         if (!event)
     388                 :          0 :                 return;
     389                 :          0 :         entry   = ring_buffer_event_data(event);
     390                 :          0 :         entry->prev_pid                      = prev->pid;
     391                 :          0 :         entry->prev_prio             = prev->prio;
     392                 :          0 :         entry->prev_state            = task_state_index(prev);
     393                 :          0 :         entry->next_pid                      = next->pid;
     394                 :          0 :         entry->next_prio             = next->prio;
     395                 :          0 :         entry->next_state            = task_state_index(next);
     396                 :          0 :         entry->next_cpu      = task_cpu(next);
     397                 :            : 
     398                 :          0 :         if (!call_filter_check_discard(call, entry, buffer, event))
     399                 :            :                 trace_buffer_unlock_commit(tr, buffer, event, flags, pc);
     400                 :            : }
     401                 :            : 
     402                 :            : static void
     403                 :          0 : tracing_sched_wakeup_trace(struct trace_array *tr,
     404                 :            :                            struct task_struct *wakee,
     405                 :            :                            struct task_struct *curr,
     406                 :            :                            unsigned long flags, int pc)
     407                 :            : {
     408                 :            :         struct trace_event_call *call = &event_wakeup;
     409                 :            :         struct ring_buffer_event *event;
     410                 :            :         struct ctx_switch_entry *entry;
     411                 :          0 :         struct ring_buffer *buffer = tr->trace_buffer.buffer;
     412                 :            : 
     413                 :          0 :         event = trace_buffer_lock_reserve(buffer, TRACE_WAKE,
     414                 :            :                                           sizeof(*entry), flags, pc);
     415                 :          0 :         if (!event)
     416                 :          0 :                 return;
     417                 :          0 :         entry   = ring_buffer_event_data(event);
     418                 :          0 :         entry->prev_pid                      = curr->pid;
     419                 :          0 :         entry->prev_prio             = curr->prio;
     420                 :          0 :         entry->prev_state            = task_state_index(curr);
     421                 :          0 :         entry->next_pid                      = wakee->pid;
     422                 :          0 :         entry->next_prio             = wakee->prio;
     423                 :          0 :         entry->next_state            = task_state_index(wakee);
     424                 :          0 :         entry->next_cpu                      = task_cpu(wakee);
     425                 :            : 
     426                 :          0 :         if (!call_filter_check_discard(call, entry, buffer, event))
     427                 :            :                 trace_buffer_unlock_commit(tr, buffer, event, flags, pc);
     428                 :            : }
     429                 :            : 
     430                 :            : static void notrace
     431                 :          0 : probe_wakeup_sched_switch(void *ignore, bool preempt,
     432                 :            :                           struct task_struct *prev, struct task_struct *next)
     433                 :            : {
     434                 :            :         struct trace_array_cpu *data;
     435                 :            :         u64 T0, T1, delta;
     436                 :            :         unsigned long flags;
     437                 :            :         long disabled;
     438                 :            :         int cpu;
     439                 :            :         int pc;
     440                 :            : 
     441                 :          0 :         tracing_record_cmdline(prev);
     442                 :            : 
     443                 :          0 :         if (unlikely(!tracer_enabled))
     444                 :            :                 return;
     445                 :            : 
     446                 :            :         /*
     447                 :            :          * When we start a new trace, we set wakeup_task to NULL
     448                 :            :          * and then set tracer_enabled = 1. We want to make sure
     449                 :            :          * that another CPU does not see the tracer_enabled = 1
     450                 :            :          * and the wakeup_task with an older task, that might
     451                 :            :          * actually be the same as next.
     452                 :            :          */
     453                 :          0 :         smp_rmb();
     454                 :            : 
     455                 :          0 :         if (next != wakeup_task)
     456                 :            :                 return;
     457                 :            : 
     458                 :            :         pc = preempt_count();
     459                 :            : 
     460                 :            :         /* disable local data, not wakeup_cpu data */
     461                 :          0 :         cpu = raw_smp_processor_id();
     462                 :          0 :         disabled = atomic_inc_return(&per_cpu_ptr(wakeup_trace->trace_buffer.data, cpu)->disabled);
     463                 :          0 :         if (likely(disabled != 1))
     464                 :            :                 goto out;
     465                 :            : 
     466                 :          0 :         local_irq_save(flags);
     467                 :          0 :         arch_spin_lock(&wakeup_lock);
     468                 :            : 
     469                 :            :         /* We could race with grabbing wakeup_lock */
     470                 :          0 :         if (unlikely(!tracer_enabled || next != wakeup_task))
     471                 :            :                 goto out_unlock;
     472                 :            : 
     473                 :            :         /* The task we are waiting for is waking up */
     474                 :          0 :         data = per_cpu_ptr(wakeup_trace->trace_buffer.data, wakeup_cpu);
     475                 :            : 
     476                 :          0 :         __trace_function(wakeup_trace, CALLER_ADDR0, CALLER_ADDR1, flags, pc);
     477                 :          0 :         tracing_sched_switch_trace(wakeup_trace, prev, next, flags, pc);
     478                 :          0 :         __trace_stack(wakeup_trace, flags, 0, pc);
     479                 :            : 
     480                 :          0 :         T0 = data->preempt_timestamp;
     481                 :          0 :         T1 = ftrace_now(cpu);
     482                 :          0 :         delta = T1-T0;
     483                 :            : 
     484                 :          0 :         if (!report_latency(wakeup_trace, delta))
     485                 :            :                 goto out_unlock;
     486                 :            : 
     487                 :          0 :         if (likely(!is_tracing_stopped())) {
     488                 :          0 :                 wakeup_trace->max_latency = delta;
     489                 :          0 :                 update_max_tr(wakeup_trace, wakeup_task, wakeup_cpu, NULL);
     490                 :            :         }
     491                 :            : 
     492                 :            : out_unlock:
     493                 :          0 :         __wakeup_reset(wakeup_trace);
     494                 :            :         arch_spin_unlock(&wakeup_lock);
     495                 :          0 :         local_irq_restore(flags);
     496                 :            : out:
     497                 :          0 :         atomic_dec(&per_cpu_ptr(wakeup_trace->trace_buffer.data, cpu)->disabled);
     498                 :            : }
     499                 :            : 
     500                 :          0 : static void __wakeup_reset(struct trace_array *tr)
     501                 :            : {
     502                 :          0 :         wakeup_cpu = -1;
     503                 :          0 :         wakeup_prio = -1;
     504                 :          0 :         tracing_dl = 0;
     505                 :            : 
     506                 :          0 :         if (wakeup_task)
     507                 :          0 :                 put_task_struct(wakeup_task);
     508                 :            : 
     509                 :          0 :         wakeup_task = NULL;
     510                 :          0 : }
     511                 :            : 
     512                 :          0 : static void wakeup_reset(struct trace_array *tr)
     513                 :            : {
     514                 :            :         unsigned long flags;
     515                 :            : 
     516                 :          0 :         tracing_reset_online_cpus(&tr->trace_buffer);
     517                 :            : 
     518                 :          0 :         local_irq_save(flags);
     519                 :          0 :         arch_spin_lock(&wakeup_lock);
     520                 :          0 :         __wakeup_reset(tr);
     521                 :            :         arch_spin_unlock(&wakeup_lock);
     522                 :          0 :         local_irq_restore(flags);
     523                 :          0 : }
     524                 :            : 
     525                 :            : static void
     526                 :          0 : probe_wakeup(void *ignore, struct task_struct *p)
     527                 :            : {
     528                 :            :         struct trace_array_cpu *data;
     529                 :          0 :         int cpu = smp_processor_id();
     530                 :            :         unsigned long flags;
     531                 :            :         long disabled;
     532                 :            :         int pc;
     533                 :            : 
     534                 :          0 :         if (likely(!tracer_enabled))
     535                 :            :                 return;
     536                 :            : 
     537                 :          0 :         tracing_record_cmdline(p);
     538                 :          0 :         tracing_record_cmdline(current);
     539                 :            : 
     540                 :            :         /*
     541                 :            :          * Semantic is like this:
     542                 :            :          *  - wakeup tracer handles all tasks in the system, independently
     543                 :            :          *    from their scheduling class;
     544                 :            :          *  - wakeup_rt tracer handles tasks belonging to sched_dl and
     545                 :            :          *    sched_rt class;
     546                 :            :          *  - wakeup_dl handles tasks belonging to sched_dl class only.
     547                 :            :          */
     548                 :          0 :         if (tracing_dl || (wakeup_dl && !dl_task(p)) ||
     549                 :          0 :             (wakeup_rt && !dl_task(p) && !rt_task(p)) ||
     550                 :          0 :             (!dl_task(p) && (p->prio >= wakeup_prio || p->prio >= current->prio)))
     551                 :            :                 return;
     552                 :            : 
     553                 :            :         pc = preempt_count();
     554                 :          0 :         disabled = atomic_inc_return(&per_cpu_ptr(wakeup_trace->trace_buffer.data, cpu)->disabled);
     555                 :          0 :         if (unlikely(disabled != 1))
     556                 :            :                 goto out;
     557                 :            : 
     558                 :            :         /* interrupts should be off from try_to_wake_up */
     559                 :          0 :         arch_spin_lock(&wakeup_lock);
     560                 :            : 
     561                 :            :         /* check for races. */
     562                 :          0 :         if (!tracer_enabled || tracing_dl ||
     563                 :          0 :             (!dl_task(p) && p->prio >= wakeup_prio))
     564                 :            :                 goto out_locked;
     565                 :            : 
     566                 :            :         /* reset the trace */
     567                 :          0 :         __wakeup_reset(wakeup_trace);
     568                 :            : 
     569                 :          0 :         wakeup_cpu = task_cpu(p);
     570                 :          0 :         wakeup_current_cpu = wakeup_cpu;
     571                 :          0 :         wakeup_prio = p->prio;
     572                 :            : 
     573                 :            :         /*
     574                 :            :          * Once you start tracing a -deadline task, don't bother tracing
     575                 :            :          * another task until the first one wakes up.
     576                 :            :          */
     577                 :          0 :         if (dl_task(p))
     578                 :          0 :                 tracing_dl = 1;
     579                 :            :         else
     580                 :          0 :                 tracing_dl = 0;
     581                 :            : 
     582                 :          0 :         wakeup_task = get_task_struct(p);
     583                 :            : 
     584                 :            :         local_save_flags(flags);
     585                 :            : 
     586                 :          0 :         data = per_cpu_ptr(wakeup_trace->trace_buffer.data, wakeup_cpu);
     587                 :          0 :         data->preempt_timestamp = ftrace_now(cpu);
     588                 :          0 :         tracing_sched_wakeup_trace(wakeup_trace, p, current, flags, pc);
     589                 :          0 :         __trace_stack(wakeup_trace, flags, 0, pc);
     590                 :            : 
     591                 :            :         /*
     592                 :            :          * We must be careful in using CALLER_ADDR2. But since wake_up
     593                 :            :          * is not called by an assembly function  (where as schedule is)
     594                 :            :          * it should be safe to use it here.
     595                 :            :          */
     596                 :          0 :         __trace_function(wakeup_trace, CALLER_ADDR1, CALLER_ADDR2, flags, pc);
     597                 :            : 
     598                 :            : out_locked:
     599                 :            :         arch_spin_unlock(&wakeup_lock);
     600                 :            : out:
     601                 :          0 :         atomic_dec(&per_cpu_ptr(wakeup_trace->trace_buffer.data, cpu)->disabled);
     602                 :            : }
     603                 :            : 
     604                 :          0 : static void start_wakeup_tracer(struct trace_array *tr)
     605                 :            : {
     606                 :            :         int ret;
     607                 :            : 
     608                 :            :         ret = register_trace_sched_wakeup(probe_wakeup, NULL);
     609                 :          0 :         if (ret) {
     610                 :          0 :                 pr_info("wakeup trace: Couldn't activate tracepoint"
     611                 :            :                         " probe to kernel_sched_wakeup\n");
     612                 :          0 :                 return;
     613                 :            :         }
     614                 :            : 
     615                 :            :         ret = register_trace_sched_wakeup_new(probe_wakeup, NULL);
     616                 :          0 :         if (ret) {
     617                 :          0 :                 pr_info("wakeup trace: Couldn't activate tracepoint"
     618                 :            :                         " probe to kernel_sched_wakeup_new\n");
     619                 :          0 :                 goto fail_deprobe;
     620                 :            :         }
     621                 :            : 
     622                 :            :         ret = register_trace_sched_switch(probe_wakeup_sched_switch, NULL);
     623                 :          0 :         if (ret) {
     624                 :          0 :                 pr_info("sched trace: Couldn't activate tracepoint"
     625                 :            :                         " probe to kernel_sched_switch\n");
     626                 :          0 :                 goto fail_deprobe_wake_new;
     627                 :            :         }
     628                 :            : 
     629                 :            :         ret = register_trace_sched_migrate_task(probe_wakeup_migrate_task, NULL);
     630                 :          0 :         if (ret) {
     631                 :          0 :                 pr_info("wakeup trace: Couldn't activate tracepoint"
     632                 :            :                         " probe to kernel_sched_migrate_task\n");
     633                 :            :                 goto fail_deprobe_sched_switch;
     634                 :            :         }
     635                 :            : 
     636                 :          0 :         wakeup_reset(tr);
     637                 :            : 
     638                 :            :         /*
     639                 :            :          * Don't let the tracer_enabled = 1 show up before
     640                 :            :          * the wakeup_task is reset. This may be overkill since
     641                 :            :          * wakeup_reset does a spin_unlock after setting the
     642                 :            :          * wakeup_task to NULL, but I want to be safe.
     643                 :            :          * This is a slow path anyway.
     644                 :            :          */
     645                 :          0 :         smp_wmb();
     646                 :            : 
     647                 :          0 :         if (start_func_tracer(tr, is_graph(tr)))
     648                 :          0 :                 printk(KERN_ERR "failed to start wakeup tracer\n");
     649                 :            : 
     650                 :            :         return;
     651                 :            : fail_deprobe_sched_switch:
     652                 :            :         unregister_trace_sched_switch(probe_wakeup_sched_switch, NULL);
     653                 :            : fail_deprobe_wake_new:
     654                 :            :         unregister_trace_sched_wakeup_new(probe_wakeup, NULL);
     655                 :            : fail_deprobe:
     656                 :            :         unregister_trace_sched_wakeup(probe_wakeup, NULL);
     657                 :            : }
     658                 :            : 
     659                 :          0 : static void stop_wakeup_tracer(struct trace_array *tr)
     660                 :            : {
     661                 :          0 :         tracer_enabled = 0;
     662                 :          0 :         stop_func_tracer(tr, is_graph(tr));
     663                 :            :         unregister_trace_sched_switch(probe_wakeup_sched_switch, NULL);
     664                 :            :         unregister_trace_sched_wakeup_new(probe_wakeup, NULL);
     665                 :            :         unregister_trace_sched_wakeup(probe_wakeup, NULL);
     666                 :            :         unregister_trace_sched_migrate_task(probe_wakeup_migrate_task, NULL);
     667                 :          0 : }
     668                 :            : 
     669                 :            : static bool wakeup_busy;
     670                 :            : 
     671                 :          0 : static int __wakeup_tracer_init(struct trace_array *tr)
     672                 :            : {
     673                 :          0 :         save_flags = tr->trace_flags;
     674                 :            : 
     675                 :            :         /* non overwrite screws up the latency tracers */
     676                 :          0 :         set_tracer_flag(tr, TRACE_ITER_OVERWRITE, 1);
     677                 :          0 :         set_tracer_flag(tr, TRACE_ITER_LATENCY_FMT, 1);
     678                 :            : 
     679                 :          0 :         tr->max_latency = 0;
     680                 :          0 :         wakeup_trace = tr;
     681                 :          0 :         ftrace_init_array_ops(tr, wakeup_tracer_call);
     682                 :          0 :         start_wakeup_tracer(tr);
     683                 :            : 
     684                 :          0 :         wakeup_busy = true;
     685                 :          0 :         return 0;
     686                 :            : }
     687                 :            : 
     688                 :          0 : static int wakeup_tracer_init(struct trace_array *tr)
     689                 :            : {
     690                 :          0 :         if (wakeup_busy)
     691                 :            :                 return -EBUSY;
     692                 :            : 
     693                 :          0 :         wakeup_dl = 0;
     694                 :          0 :         wakeup_rt = 0;
     695                 :          0 :         return __wakeup_tracer_init(tr);
     696                 :            : }
     697                 :            : 
     698                 :          0 : static int wakeup_rt_tracer_init(struct trace_array *tr)
     699                 :            : {
     700                 :          0 :         if (wakeup_busy)
     701                 :            :                 return -EBUSY;
     702                 :            : 
     703                 :          0 :         wakeup_dl = 0;
     704                 :          0 :         wakeup_rt = 1;
     705                 :          0 :         return __wakeup_tracer_init(tr);
     706                 :            : }
     707                 :            : 
     708                 :          0 : static int wakeup_dl_tracer_init(struct trace_array *tr)
     709                 :            : {
     710                 :          0 :         if (wakeup_busy)
     711                 :            :                 return -EBUSY;
     712                 :            : 
     713                 :          0 :         wakeup_dl = 1;
     714                 :          0 :         wakeup_rt = 0;
     715                 :          0 :         return __wakeup_tracer_init(tr);
     716                 :            : }
     717                 :            : 
     718                 :          0 : static void wakeup_tracer_reset(struct trace_array *tr)
     719                 :            : {
     720                 :          0 :         int lat_flag = save_flags & TRACE_ITER_LATENCY_FMT;
     721                 :          0 :         int overwrite_flag = save_flags & TRACE_ITER_OVERWRITE;
     722                 :            : 
     723                 :          0 :         stop_wakeup_tracer(tr);
     724                 :            :         /* make sure we put back any tasks we are tracing */
     725                 :          0 :         wakeup_reset(tr);
     726                 :            : 
     727                 :          0 :         set_tracer_flag(tr, TRACE_ITER_LATENCY_FMT, lat_flag);
     728                 :          0 :         set_tracer_flag(tr, TRACE_ITER_OVERWRITE, overwrite_flag);
     729                 :          0 :         ftrace_reset_array_ops(tr);
     730                 :          0 :         wakeup_busy = false;
     731                 :          0 : }
     732                 :            : 
     733                 :          0 : static void wakeup_tracer_start(struct trace_array *tr)
     734                 :            : {
     735                 :          0 :         wakeup_reset(tr);
     736                 :          0 :         tracer_enabled = 1;
     737                 :          0 : }
     738                 :            : 
     739                 :          0 : static void wakeup_tracer_stop(struct trace_array *tr)
     740                 :            : {
     741                 :          0 :         tracer_enabled = 0;
     742                 :          0 : }
     743                 :            : 
     744                 :            : static struct tracer wakeup_tracer __read_mostly =
     745                 :            : {
     746                 :            :         .name           = "wakeup",
     747                 :            :         .init           = wakeup_tracer_init,
     748                 :            :         .reset          = wakeup_tracer_reset,
     749                 :            :         .start          = wakeup_tracer_start,
     750                 :            :         .stop           = wakeup_tracer_stop,
     751                 :            :         .print_max      = true,
     752                 :            :         .print_header   = wakeup_print_header,
     753                 :            :         .print_line     = wakeup_print_line,
     754                 :            :         .flag_changed   = wakeup_flag_changed,
     755                 :            : #ifdef CONFIG_FTRACE_SELFTEST
     756                 :            :         .selftest    = trace_selftest_startup_wakeup,
     757                 :            : #endif
     758                 :            :         .open           = wakeup_trace_open,
     759                 :            :         .close          = wakeup_trace_close,
     760                 :            :         .allow_instances = true,
     761                 :            :         .use_max_tr     = true,
     762                 :            : };
     763                 :            : 
     764                 :            : static struct tracer wakeup_rt_tracer __read_mostly =
     765                 :            : {
     766                 :            :         .name           = "wakeup_rt",
     767                 :            :         .init           = wakeup_rt_tracer_init,
     768                 :            :         .reset          = wakeup_tracer_reset,
     769                 :            :         .start          = wakeup_tracer_start,
     770                 :            :         .stop           = wakeup_tracer_stop,
     771                 :            :         .print_max      = true,
     772                 :            :         .print_header   = wakeup_print_header,
     773                 :            :         .print_line     = wakeup_print_line,
     774                 :            :         .flag_changed   = wakeup_flag_changed,
     775                 :            : #ifdef CONFIG_FTRACE_SELFTEST
     776                 :            :         .selftest    = trace_selftest_startup_wakeup,
     777                 :            : #endif
     778                 :            :         .open           = wakeup_trace_open,
     779                 :            :         .close          = wakeup_trace_close,
     780                 :            :         .allow_instances = true,
     781                 :            :         .use_max_tr     = true,
     782                 :            : };
     783                 :            : 
     784                 :            : static struct tracer wakeup_dl_tracer __read_mostly =
     785                 :            : {
     786                 :            :         .name           = "wakeup_dl",
     787                 :            :         .init           = wakeup_dl_tracer_init,
     788                 :            :         .reset          = wakeup_tracer_reset,
     789                 :            :         .start          = wakeup_tracer_start,
     790                 :            :         .stop           = wakeup_tracer_stop,
     791                 :            :         .print_max      = true,
     792                 :            :         .print_header   = wakeup_print_header,
     793                 :            :         .print_line     = wakeup_print_line,
     794                 :            :         .flag_changed   = wakeup_flag_changed,
     795                 :            : #ifdef CONFIG_FTRACE_SELFTEST
     796                 :            :         .selftest    = trace_selftest_startup_wakeup,
     797                 :            : #endif
     798                 :            :         .open           = wakeup_trace_open,
     799                 :            :         .close          = wakeup_trace_close,
     800                 :            :         .allow_instances = true,
     801                 :            :         .use_max_tr     = true,
     802                 :            : };
     803                 :            : 
     804                 :          3 : __init static int init_wakeup_tracer(void)
     805                 :            : {
     806                 :            :         int ret;
     807                 :            : 
     808                 :          3 :         ret = register_tracer(&wakeup_tracer);
     809                 :          3 :         if (ret)
     810                 :            :                 return ret;
     811                 :            : 
     812                 :          3 :         ret = register_tracer(&wakeup_rt_tracer);
     813                 :          3 :         if (ret)
     814                 :            :                 return ret;
     815                 :            : 
     816                 :          3 :         ret = register_tracer(&wakeup_dl_tracer);
     817                 :          3 :         if (ret)
     818                 :          0 :                 return ret;
     819                 :            : 
     820                 :            :         return 0;
     821                 :            : }
     822                 :            : core_initcall(init_wakeup_tracer);
    

Generated by: LCOV version 1.14