LCOV - code coverage report
Current view: top level - drivers/oprofile - buffer_sync.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 195 0.0 %
Date: 2014-02-18 Functions: 0 20 0.0 %
Branches: 0 100 0.0 %

           Branch data     Line data    Source code
       1                 :            : /**
       2                 :            :  * @file buffer_sync.c
       3                 :            :  *
       4                 :            :  * @remark Copyright 2002-2009 OProfile authors
       5                 :            :  * @remark Read the file COPYING
       6                 :            :  *
       7                 :            :  * @author John Levon <levon@movementarian.org>
       8                 :            :  * @author Barry Kasindorf
       9                 :            :  * @author Robert Richter <robert.richter@amd.com>
      10                 :            :  *
      11                 :            :  * This is the core of the buffer management. Each
      12                 :            :  * CPU buffer is processed and entered into the
      13                 :            :  * global event buffer. Such processing is necessary
      14                 :            :  * in several circumstances, mentioned below.
      15                 :            :  *
      16                 :            :  * The processing does the job of converting the
      17                 :            :  * transitory EIP value into a persistent dentry/offset
      18                 :            :  * value that the profiler can record at its leisure.
      19                 :            :  *
      20                 :            :  * See fs/dcookies.c for a description of the dentry/offset
      21                 :            :  * objects.
      22                 :            :  */
      23                 :            : 
      24                 :            : #include <linux/mm.h>
      25                 :            : #include <linux/workqueue.h>
      26                 :            : #include <linux/notifier.h>
      27                 :            : #include <linux/dcookies.h>
      28                 :            : #include <linux/profile.h>
      29                 :            : #include <linux/module.h>
      30                 :            : #include <linux/fs.h>
      31                 :            : #include <linux/oprofile.h>
      32                 :            : #include <linux/sched.h>
      33                 :            : #include <linux/gfp.h>
      34                 :            : 
      35                 :            : #include "oprofile_stats.h"
      36                 :            : #include "event_buffer.h"
      37                 :            : #include "cpu_buffer.h"
      38                 :            : #include "buffer_sync.h"
      39                 :            : 
      40                 :            : static LIST_HEAD(dying_tasks);
      41                 :            : static LIST_HEAD(dead_tasks);
      42                 :            : static cpumask_var_t marked_cpus;
      43                 :            : static DEFINE_SPINLOCK(task_mortuary);
      44                 :            : static void process_task_mortuary(void);
      45                 :            : 
      46                 :            : /* Take ownership of the task struct and place it on the
      47                 :            :  * list for processing. Only after two full buffer syncs
      48                 :            :  * does the task eventually get freed, because by then
      49                 :            :  * we are sure we will not reference it again.
      50                 :            :  * Can be invoked from softirq via RCU callback due to
      51                 :            :  * call_rcu() of the task struct, hence the _irqsave.
      52                 :            :  */
      53                 :            : static int
      54                 :          0 : task_free_notify(struct notifier_block *self, unsigned long val, void *data)
      55                 :            : {
      56                 :            :         unsigned long flags;
      57                 :            :         struct task_struct *task = data;
      58                 :          0 :         spin_lock_irqsave(&task_mortuary, flags);
      59                 :          0 :         list_add(&task->tasks, &dying_tasks);
      60                 :            :         spin_unlock_irqrestore(&task_mortuary, flags);
      61                 :          0 :         return NOTIFY_OK;
      62                 :            : }
      63                 :            : 
      64                 :            : 
      65                 :            : /* The task is on its way out. A sync of the buffer means we can catch
      66                 :            :  * any remaining samples for this task.
      67                 :            :  */
      68                 :            : static int
      69                 :          0 : task_exit_notify(struct notifier_block *self, unsigned long val, void *data)
      70                 :            : {
      71                 :            :         /* To avoid latency problems, we only process the current CPU,
      72                 :            :          * hoping that most samples for the task are on this CPU
      73                 :            :          */
      74                 :          0 :         sync_buffer(raw_smp_processor_id());
      75                 :          0 :         return 0;
      76                 :            : }
      77                 :            : 
      78                 :            : 
      79                 :            : /* The task is about to try a do_munmap(). We peek at what it's going to
      80                 :            :  * do, and if it's an executable region, process the samples first, so
      81                 :            :  * we don't lose any. This does not have to be exact, it's a QoI issue
      82                 :            :  * only.
      83                 :            :  */
      84                 :            : static int
      85                 :          0 : munmap_notify(struct notifier_block *self, unsigned long val, void *data)
      86                 :            : {
      87                 :          0 :         unsigned long addr = (unsigned long)data;
      88                 :          0 :         struct mm_struct *mm = current->mm;
      89                 :            :         struct vm_area_struct *mpnt;
      90                 :            : 
      91                 :          0 :         down_read(&mm->mmap_sem);
      92                 :            : 
      93                 :          0 :         mpnt = find_vma(mm, addr);
      94 [ #  # ][ #  # ]:          0 :         if (mpnt && mpnt->vm_file && (mpnt->vm_flags & VM_EXEC)) {
                 [ #  # ]
      95                 :          0 :                 up_read(&mm->mmap_sem);
      96                 :            :                 /* To avoid latency problems, we only process the current CPU,
      97                 :            :                  * hoping that most samples for the task are on this CPU
      98                 :            :                  */
      99                 :          0 :                 sync_buffer(raw_smp_processor_id());
     100                 :          0 :                 return 0;
     101                 :            :         }
     102                 :            : 
     103                 :          0 :         up_read(&mm->mmap_sem);
     104                 :          0 :         return 0;
     105                 :            : }
     106                 :            : 
     107                 :            : 
     108                 :            : /* We need to be told about new modules so we don't attribute to a previously
     109                 :            :  * loaded module, or drop the samples on the floor.
     110                 :            :  */
     111                 :            : static int
     112                 :          0 : module_load_notify(struct notifier_block *self, unsigned long val, void *data)
     113                 :            : {
     114                 :            : #ifdef CONFIG_MODULES
     115         [ #  # ]:          0 :         if (val != MODULE_STATE_COMING)
     116                 :            :                 return 0;
     117                 :            : 
     118                 :            :         /* FIXME: should we process all CPU buffers ? */
     119                 :          0 :         mutex_lock(&buffer_mutex);
     120                 :          0 :         add_event_entry(ESCAPE_CODE);
     121                 :          0 :         add_event_entry(MODULE_LOADED_CODE);
     122                 :          0 :         mutex_unlock(&buffer_mutex);
     123                 :            : #endif
     124                 :          0 :         return 0;
     125                 :            : }
     126                 :            : 
     127                 :            : 
     128                 :            : static struct notifier_block task_free_nb = {
     129                 :            :         .notifier_call  = task_free_notify,
     130                 :            : };
     131                 :            : 
     132                 :            : static struct notifier_block task_exit_nb = {
     133                 :            :         .notifier_call  = task_exit_notify,
     134                 :            : };
     135                 :            : 
     136                 :            : static struct notifier_block munmap_nb = {
     137                 :            :         .notifier_call  = munmap_notify,
     138                 :            : };
     139                 :            : 
     140                 :            : static struct notifier_block module_load_nb = {
     141                 :            :         .notifier_call = module_load_notify,
     142                 :            : };
     143                 :            : 
     144                 :            : static void free_all_tasks(void)
     145                 :            : {
     146                 :            :         /* make sure we don't leak task structs */
     147                 :          0 :         process_task_mortuary();
     148                 :          0 :         process_task_mortuary();
     149                 :            : }
     150                 :            : 
     151                 :          0 : int sync_start(void)
     152                 :            : {
     153                 :            :         int err;
     154                 :            : 
     155                 :            :         if (!zalloc_cpumask_var(&marked_cpus, GFP_KERNEL))
     156                 :            :                 return -ENOMEM;
     157                 :            : 
     158                 :          0 :         err = task_handoff_register(&task_free_nb);
     159         [ #  # ]:          0 :         if (err)
     160                 :            :                 goto out1;
     161                 :          0 :         err = profile_event_register(PROFILE_TASK_EXIT, &task_exit_nb);
     162         [ #  # ]:          0 :         if (err)
     163                 :            :                 goto out2;
     164                 :          0 :         err = profile_event_register(PROFILE_MUNMAP, &munmap_nb);
     165         [ #  # ]:          0 :         if (err)
     166                 :            :                 goto out3;
     167                 :          0 :         err = register_module_notifier(&module_load_nb);
     168         [ #  # ]:          0 :         if (err)
     169                 :            :                 goto out4;
     170                 :            : 
     171                 :          0 :         start_cpu_work();
     172                 :            : 
     173                 :            : out:
     174                 :            :         return err;
     175                 :            : out4:
     176                 :          0 :         profile_event_unregister(PROFILE_MUNMAP, &munmap_nb);
     177                 :            : out3:
     178                 :          0 :         profile_event_unregister(PROFILE_TASK_EXIT, &task_exit_nb);
     179                 :            : out2:
     180                 :          0 :         task_handoff_unregister(&task_free_nb);
     181                 :            :         free_all_tasks();
     182                 :            : out1:
     183                 :            :         free_cpumask_var(marked_cpus);
     184                 :            :         goto out;
     185                 :            : }
     186                 :            : 
     187                 :            : 
     188                 :          0 : void sync_stop(void)
     189                 :            : {
     190                 :          0 :         end_cpu_work();
     191                 :          0 :         unregister_module_notifier(&module_load_nb);
     192                 :          0 :         profile_event_unregister(PROFILE_MUNMAP, &munmap_nb);
     193                 :          0 :         profile_event_unregister(PROFILE_TASK_EXIT, &task_exit_nb);
     194                 :          0 :         task_handoff_unregister(&task_free_nb);
     195                 :          0 :         barrier();                      /* do all of the above first */
     196                 :            : 
     197                 :          0 :         flush_cpu_work();
     198                 :            : 
     199                 :            :         free_all_tasks();
     200                 :            :         free_cpumask_var(marked_cpus);
     201                 :          0 : }
     202                 :            : 
     203                 :            : 
     204                 :            : /* Optimisation. We can manage without taking the dcookie sem
     205                 :            :  * because we cannot reach this code without at least one
     206                 :            :  * dcookie user still being registered (namely, the reader
     207                 :            :  * of the event buffer). */
     208                 :            : static inline unsigned long fast_get_dcookie(struct path *path)
     209                 :            : {
     210                 :            :         unsigned long cookie;
     211                 :            : 
     212 [ #  # ][ #  # ]:          0 :         if (path->dentry->d_flags & DCACHE_COOKIE)
     213                 :          0 :                 return (unsigned long)path->dentry;
     214                 :          0 :         get_dcookie(path, &cookie);
     215                 :          0 :         return cookie;
     216                 :            : }
     217                 :            : 
     218                 :            : 
     219                 :            : /* Look up the dcookie for the task's mm->exe_file,
     220                 :            :  * which corresponds loosely to "application name". This is
     221                 :            :  * not strictly necessary but allows oprofile to associate
     222                 :            :  * shared-library samples with particular applications
     223                 :            :  */
     224                 :          0 : static unsigned long get_exec_dcookie(struct mm_struct *mm)
     225                 :            : {
     226                 :            :         unsigned long cookie = NO_COOKIE;
     227                 :            : 
     228 [ #  # ][ #  # ]:          0 :         if (mm && mm->exe_file)
     229                 :          0 :                 cookie = fast_get_dcookie(&mm->exe_file->f_path);
     230                 :            : 
     231                 :          0 :         return cookie;
     232                 :            : }
     233                 :            : 
     234                 :            : 
     235                 :            : /* Convert the EIP value of a sample into a persistent dentry/offset
     236                 :            :  * pair that can then be added to the global event buffer. We make
     237                 :            :  * sure to do this lookup before a mm->mmap modification happens so
     238                 :            :  * we don't lose track.
     239                 :            :  */
     240                 :            : static unsigned long
     241                 :          0 : lookup_dcookie(struct mm_struct *mm, unsigned long addr, off_t *offset)
     242                 :            : {
     243                 :            :         unsigned long cookie = NO_COOKIE;
     244                 :            :         struct vm_area_struct *vma;
     245                 :            : 
     246         [ #  # ]:          0 :         for (vma = find_vma(mm, addr); vma; vma = vma->vm_next) {
     247                 :            : 
     248 [ #  # ][ #  # ]:          0 :                 if (addr < vma->vm_start || addr >= vma->vm_end)
     249                 :          0 :                         continue;
     250                 :            : 
     251         [ #  # ]:          0 :                 if (vma->vm_file) {
     252                 :          0 :                         cookie = fast_get_dcookie(&vma->vm_file->f_path);
     253                 :          0 :                         *offset = (vma->vm_pgoff << PAGE_SHIFT) + addr -
     254                 :          0 :                                 vma->vm_start;
     255                 :            :                 } else {
     256                 :            :                         /* must be an anonymous map */
     257                 :          0 :                         *offset = addr;
     258                 :            :                 }
     259                 :            : 
     260                 :            :                 break;
     261                 :            :         }
     262                 :            : 
     263         [ #  # ]:          0 :         if (!vma)
     264                 :            :                 cookie = INVALID_COOKIE;
     265                 :            : 
     266                 :          0 :         return cookie;
     267                 :            : }
     268                 :            : 
     269                 :            : static unsigned long last_cookie = INVALID_COOKIE;
     270                 :            : 
     271                 :          0 : static void add_cpu_switch(int i)
     272                 :            : {
     273                 :          0 :         add_event_entry(ESCAPE_CODE);
     274                 :          0 :         add_event_entry(CPU_SWITCH_CODE);
     275                 :          0 :         add_event_entry(i);
     276                 :          0 :         last_cookie = INVALID_COOKIE;
     277                 :          0 : }
     278                 :            : 
     279                 :          0 : static void add_kernel_ctx_switch(unsigned int in_kernel)
     280                 :            : {
     281                 :          0 :         add_event_entry(ESCAPE_CODE);
     282         [ #  # ]:          0 :         if (in_kernel)
     283                 :          0 :                 add_event_entry(KERNEL_ENTER_SWITCH_CODE);
     284                 :            :         else
     285                 :          0 :                 add_event_entry(KERNEL_EXIT_SWITCH_CODE);
     286                 :          0 : }
     287                 :            : 
     288                 :            : static void
     289                 :          0 : add_user_ctx_switch(struct task_struct const *task, unsigned long cookie)
     290                 :            : {
     291                 :          0 :         add_event_entry(ESCAPE_CODE);
     292                 :          0 :         add_event_entry(CTX_SWITCH_CODE);
     293                 :          0 :         add_event_entry(task->pid);
     294                 :          0 :         add_event_entry(cookie);
     295                 :            :         /* Another code for daemon back-compat */
     296                 :          0 :         add_event_entry(ESCAPE_CODE);
     297                 :          0 :         add_event_entry(CTX_TGID_CODE);
     298                 :          0 :         add_event_entry(task->tgid);
     299                 :          0 : }
     300                 :            : 
     301                 :            : 
     302                 :          0 : static void add_cookie_switch(unsigned long cookie)
     303                 :            : {
     304                 :          0 :         add_event_entry(ESCAPE_CODE);
     305                 :          0 :         add_event_entry(COOKIE_SWITCH_CODE);
     306                 :          0 :         add_event_entry(cookie);
     307                 :          0 : }
     308                 :            : 
     309                 :            : 
     310                 :            : static void add_trace_begin(void)
     311                 :            : {
     312                 :          0 :         add_event_entry(ESCAPE_CODE);
     313                 :          0 :         add_event_entry(TRACE_BEGIN_CODE);
     314                 :            : }
     315                 :            : 
     316                 :          0 : static void add_data(struct op_entry *entry, struct mm_struct *mm)
     317                 :            : {
     318                 :            :         unsigned long code, pc, val;
     319                 :            :         unsigned long cookie;
     320                 :            :         off_t offset;
     321                 :            : 
     322         [ #  # ]:          0 :         if (!op_cpu_buffer_get_data(entry, &code))
     323                 :          0 :                 return;
     324         [ #  # ]:          0 :         if (!op_cpu_buffer_get_data(entry, &pc))
     325                 :            :                 return;
     326         [ #  # ]:          0 :         if (!op_cpu_buffer_get_size(entry))
     327                 :            :                 return;
     328                 :            : 
     329         [ #  # ]:          0 :         if (mm) {
     330                 :          0 :                 cookie = lookup_dcookie(mm, pc, &offset);
     331                 :            : 
     332         [ #  # ]:          0 :                 if (cookie == NO_COOKIE)
     333                 :          0 :                         offset = pc;
     334         [ #  # ]:          0 :                 if (cookie == INVALID_COOKIE) {
     335                 :            :                         atomic_inc(&oprofile_stats.sample_lost_no_mapping);
     336                 :          0 :                         offset = pc;
     337                 :            :                 }
     338         [ #  # ]:          0 :                 if (cookie != last_cookie) {
     339                 :          0 :                         add_cookie_switch(cookie);
     340                 :          0 :                         last_cookie = cookie;
     341                 :            :                 }
     342                 :            :         } else
     343                 :          0 :                 offset = pc;
     344                 :            : 
     345                 :          0 :         add_event_entry(ESCAPE_CODE);
     346                 :          0 :         add_event_entry(code);
     347                 :          0 :         add_event_entry(offset);        /* Offset from Dcookie */
     348                 :            : 
     349         [ #  # ]:          0 :         while (op_cpu_buffer_get_data(entry, &val))
     350                 :          0 :                 add_event_entry(val);
     351                 :            : }
     352                 :            : 
     353                 :            : static inline void add_sample_entry(unsigned long offset, unsigned long event)
     354                 :            : {
     355                 :          0 :         add_event_entry(offset);
     356                 :          0 :         add_event_entry(event);
     357                 :            : }
     358                 :            : 
     359                 :            : 
     360                 :            : /*
     361                 :            :  * Add a sample to the global event buffer. If possible the
     362                 :            :  * sample is converted into a persistent dentry/offset pair
     363                 :            :  * for later lookup from userspace. Return 0 on failure.
     364                 :            :  */
     365                 :            : static int
     366                 :          0 : add_sample(struct mm_struct *mm, struct op_sample *s, int in_kernel)
     367                 :            : {
     368                 :            :         unsigned long cookie;
     369                 :            :         off_t offset;
     370                 :            : 
     371         [ #  # ]:          0 :         if (in_kernel) {
     372                 :          0 :                 add_sample_entry(s->eip, s->event);
     373                 :          0 :                 return 1;
     374                 :            :         }
     375                 :            : 
     376                 :            :         /* add userspace sample */
     377                 :            : 
     378         [ #  # ]:          0 :         if (!mm) {
     379                 :            :                 atomic_inc(&oprofile_stats.sample_lost_no_mm);
     380                 :          0 :                 return 0;
     381                 :            :         }
     382                 :            : 
     383                 :          0 :         cookie = lookup_dcookie(mm, s->eip, &offset);
     384                 :            : 
     385         [ #  # ]:          0 :         if (cookie == INVALID_COOKIE) {
     386                 :            :                 atomic_inc(&oprofile_stats.sample_lost_no_mapping);
     387                 :          0 :                 return 0;
     388                 :            :         }
     389                 :            : 
     390         [ #  # ]:          0 :         if (cookie != last_cookie) {
     391                 :          0 :                 add_cookie_switch(cookie);
     392                 :          0 :                 last_cookie = cookie;
     393                 :            :         }
     394                 :            : 
     395                 :          0 :         add_sample_entry(offset, s->event);
     396                 :            : 
     397                 :          0 :         return 1;
     398                 :            : }
     399                 :            : 
     400                 :            : 
     401                 :          0 : static void release_mm(struct mm_struct *mm)
     402                 :            : {
     403         [ #  # ]:          0 :         if (!mm)
     404                 :          0 :                 return;
     405                 :          0 :         up_read(&mm->mmap_sem);
     406                 :          0 :         mmput(mm);
     407                 :            : }
     408                 :            : 
     409                 :            : 
     410                 :          0 : static struct mm_struct *take_tasks_mm(struct task_struct *task)
     411                 :            : {
     412                 :          0 :         struct mm_struct *mm = get_task_mm(task);
     413         [ #  # ]:          0 :         if (mm)
     414                 :          0 :                 down_read(&mm->mmap_sem);
     415                 :          0 :         return mm;
     416                 :            : }
     417                 :            : 
     418                 :            : 
     419                 :            : static inline int is_code(unsigned long val)
     420                 :            : {
     421                 :            :         return val == ESCAPE_CODE;
     422                 :            : }
     423                 :            : 
     424                 :            : 
     425                 :            : /* Move tasks along towards death. Any tasks on dead_tasks
     426                 :            :  * will definitely have no remaining references in any
     427                 :            :  * CPU buffers at this point, because we use two lists,
     428                 :            :  * and to have reached the list, it must have gone through
     429                 :            :  * one full sync already.
     430                 :            :  */
     431                 :          0 : static void process_task_mortuary(void)
     432                 :            : {
     433                 :            :         unsigned long flags;
     434                 :          0 :         LIST_HEAD(local_dead_tasks);
     435                 :            :         struct task_struct *task;
     436                 :            :         struct task_struct *ttask;
     437                 :            : 
     438                 :          0 :         spin_lock_irqsave(&task_mortuary, flags);
     439                 :            : 
     440                 :            :         list_splice_init(&dead_tasks, &local_dead_tasks);
     441                 :            :         list_splice_init(&dying_tasks, &dead_tasks);
     442                 :            : 
     443                 :            :         spin_unlock_irqrestore(&task_mortuary, flags);
     444                 :            : 
     445         [ #  # ]:          0 :         list_for_each_entry_safe(task, ttask, &local_dead_tasks, tasks) {
     446                 :            :                 list_del(&task->tasks);
     447                 :          0 :                 free_task(task);
     448                 :            :         }
     449                 :          0 : }
     450                 :            : 
     451                 :            : 
     452                 :          0 : static void mark_done(int cpu)
     453                 :            : {
     454                 :            :         int i;
     455                 :            : 
     456                 :            :         cpumask_set_cpu(cpu, marked_cpus);
     457                 :            : 
     458         [ #  # ]:          0 :         for_each_online_cpu(i) {
     459         [ #  # ]:          0 :                 if (!cpumask_test_cpu(i, marked_cpus))
     460                 :          0 :                         return;
     461                 :            :         }
     462                 :            : 
     463                 :            :         /* All CPUs have been processed at least once,
     464                 :            :          * we can process the mortuary once
     465                 :            :          */
     466                 :          0 :         process_task_mortuary();
     467                 :            : 
     468                 :            :         cpumask_clear(marked_cpus);
     469                 :            : }
     470                 :            : 
     471                 :            : 
     472                 :            : /* FIXME: this is not sufficient if we implement syscall barrier backtrace
     473                 :            :  * traversal, the code switch to sb_sample_start at first kernel enter/exit
     474                 :            :  * switch so we need a fifth state and some special handling in sync_buffer()
     475                 :            :  */
     476                 :            : typedef enum {
     477                 :            :         sb_bt_ignore = -2,
     478                 :            :         sb_buffer_start,
     479                 :            :         sb_bt_start,
     480                 :            :         sb_sample_start,
     481                 :            : } sync_buffer_state;
     482                 :            : 
     483                 :            : /* Sync one of the CPU's buffers into the global event buffer.
     484                 :            :  * Here we need to go through each batch of samples punctuated
     485                 :            :  * by context switch notes, taking the task's mmap_sem and doing
     486                 :            :  * lookup in task->mm->mmap to convert EIP into dcookie/offset
     487                 :            :  * value.
     488                 :            :  */
     489                 :          0 : void sync_buffer(int cpu)
     490                 :            : {
     491                 :            :         struct mm_struct *mm = NULL;
     492                 :            :         struct mm_struct *oldmm;
     493                 :            :         unsigned long val;
     494                 :            :         struct task_struct *new;
     495                 :            :         unsigned long cookie = 0;
     496                 :            :         int in_kernel = 1;
     497                 :            :         sync_buffer_state state = sb_buffer_start;
     498                 :            :         unsigned int i;
     499                 :            :         unsigned long available;
     500                 :            :         unsigned long flags;
     501                 :            :         struct op_entry entry;
     502                 :            :         struct op_sample *sample;
     503                 :            : 
     504                 :          0 :         mutex_lock(&buffer_mutex);
     505                 :            : 
     506                 :          0 :         add_cpu_switch(cpu);
     507                 :            : 
     508                 :            :         op_cpu_buffer_reset(cpu);
     509                 :          0 :         available = op_cpu_buffer_entries(cpu);
     510                 :            : 
     511         [ #  # ]:          0 :         for (i = 0; i < available; ++i) {
     512                 :          0 :                 sample = op_cpu_buffer_read_entry(&entry, cpu);
     513         [ #  # ]:          0 :                 if (!sample)
     514                 :            :                         break;
     515                 :            : 
     516         [ #  # ]:          0 :                 if (is_code(sample->eip)) {
     517                 :          0 :                         flags = sample->event;
     518         [ #  # ]:          0 :                         if (flags & TRACE_BEGIN) {
     519                 :            :                                 state = sb_bt_start;
     520                 :            :                                 add_trace_begin();
     521                 :            :                         }
     522         [ #  # ]:          0 :                         if (flags & KERNEL_CTX_SWITCH) {
     523                 :            :                                 /* kernel/userspace switch */
     524                 :          0 :                                 in_kernel = flags & IS_KERNEL;
     525         [ #  # ]:          0 :                                 if (state == sb_buffer_start)
     526                 :            :                                         state = sb_sample_start;
     527                 :          0 :                                 add_kernel_ctx_switch(flags & IS_KERNEL);
     528                 :            :                         }
     529         [ #  # ]:          0 :                         if (flags & USER_CTX_SWITCH
     530         [ #  # ]:          0 :                             && op_cpu_buffer_get_data(&entry, &val)) {
     531                 :            :                                 /* userspace context switch */
     532                 :          0 :                                 new = (struct task_struct *)val;
     533                 :            :                                 oldmm = mm;
     534                 :          0 :                                 release_mm(oldmm);
     535                 :          0 :                                 mm = take_tasks_mm(new);
     536         [ #  # ]:          0 :                                 if (mm != oldmm)
     537                 :          0 :                                         cookie = get_exec_dcookie(mm);
     538                 :          0 :                                 add_user_ctx_switch(new, cookie);
     539                 :            :                         }
     540         [ #  # ]:          0 :                         if (op_cpu_buffer_get_size(&entry))
     541                 :          0 :                                 add_data(&entry, mm);
     542                 :          0 :                         continue;
     543                 :            :                 }
     544                 :            : 
     545         [ #  # ]:          0 :                 if (state < sb_bt_start)
     546                 :            :                         /* ignore sample */
     547                 :          0 :                         continue;
     548                 :            : 
     549         [ #  # ]:          0 :                 if (add_sample(mm, sample, in_kernel))
     550                 :          0 :                         continue;
     551                 :            : 
     552                 :            :                 /* ignore backtraces if failed to add a sample */
     553         [ #  # ]:          0 :                 if (state == sb_bt_start) {
     554                 :            :                         state = sb_bt_ignore;
     555                 :            :                         atomic_inc(&oprofile_stats.bt_lost_no_mapping);
     556                 :            :                 }
     557                 :            :         }
     558                 :          0 :         release_mm(mm);
     559                 :            : 
     560                 :          0 :         mark_done(cpu);
     561                 :            : 
     562                 :          0 :         mutex_unlock(&buffer_mutex);
     563                 :          0 : }
     564                 :            : 
     565                 :            : /* The function can be used to add a buffer worth of data directly to
     566                 :            :  * the kernel buffer. The buffer is assumed to be a circular buffer.
     567                 :            :  * Take the entries from index start and end at index end, wrapping
     568                 :            :  * at max_entries.
     569                 :            :  */
     570                 :          0 : void oprofile_put_buff(unsigned long *buf, unsigned int start,
     571                 :            :                        unsigned int stop, unsigned int max)
     572                 :            : {
     573                 :            :         int i;
     574                 :            : 
     575                 :          0 :         i = start;
     576                 :            : 
     577                 :          0 :         mutex_lock(&buffer_mutex);
     578         [ #  # ]:          0 :         while (i != stop) {
     579                 :          0 :                 add_event_entry(buf[i++]);
     580                 :            : 
     581         [ #  # ]:          0 :                 if (i >= max)
     582                 :            :                         i = 0;
     583                 :            :         }
     584                 :            : 
     585                 :          0 :         mutex_unlock(&buffer_mutex);
     586                 :          0 : }
     587                 :            : 

Generated by: LCOV version 1.9