trace_irqsoff.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764
  1. /*
  2. * trace irqs off critical timings
  3. *
  4. * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com>
  5. * Copyright (C) 2008 Ingo Molnar <mingo@redhat.com>
  6. *
  7. * From code in the latency_tracer, that is:
  8. *
  9. * Copyright (C) 2004-2006 Ingo Molnar
  10. * Copyright (C) 2004 Nadia Yvette Chambers
  11. */
  12. #include <linux/kallsyms.h>
  13. #include <linux/uaccess.h>
  14. #include <linux/module.h>
  15. #include <linux/ftrace.h>
  16. #include "trace.h"
  17. static struct trace_array *irqsoff_trace __read_mostly;
  18. static int tracer_enabled __read_mostly;
  19. static DEFINE_PER_CPU(int, tracing_cpu);
  20. static DEFINE_RAW_SPINLOCK(max_trace_lock);
  21. enum {
  22. TRACER_IRQS_OFF = (1 << 1),
  23. TRACER_PREEMPT_OFF = (1 << 2),
  24. };
  25. static int trace_type __read_mostly;
  26. static int save_flags;
  27. static bool function_enabled;
  28. static void stop_irqsoff_tracer(struct trace_array *tr, int graph);
  29. static int start_irqsoff_tracer(struct trace_array *tr, int graph);
  30. #ifdef CONFIG_PREEMPT_TRACER
  31. static inline int
  32. preempt_trace(void)
  33. {
  34. return ((trace_type & TRACER_PREEMPT_OFF) && preempt_count());
  35. }
  36. #else
  37. # define preempt_trace() (0)
  38. #endif
  39. #ifdef CONFIG_IRQSOFF_TRACER
  40. static inline int
  41. irq_trace(void)
  42. {
  43. return ((trace_type & TRACER_IRQS_OFF) &&
  44. irqs_disabled());
  45. }
  46. #else
  47. # define irq_trace() (0)
  48. #endif
  49. #define TRACE_DISPLAY_GRAPH 1
  50. static struct tracer_opt trace_opts[] = {
  51. #ifdef CONFIG_FUNCTION_GRAPH_TRACER
  52. /* display latency trace as call graph */
  53. { TRACER_OPT(display-graph, TRACE_DISPLAY_GRAPH) },
  54. #endif
  55. { } /* Empty entry */
  56. };
  57. static struct tracer_flags tracer_flags = {
  58. .val = 0,
  59. .opts = trace_opts,
  60. };
  61. #define is_graph() (tracer_flags.val & TRACE_DISPLAY_GRAPH)
  62. /*
  63. * Sequence count - we record it when starting a measurement and
  64. * skip the latency if the sequence has changed - some other section
  65. * did a maximum and could disturb our measurement with serial console
  66. * printouts, etc. Truly coinciding maximum latencies should be rare
  67. * and what happens together happens separately as well, so this doesn't
  68. * decrease the validity of the maximum found:
  69. */
  70. static __cacheline_aligned_in_smp unsigned long max_sequence;
  71. #ifdef CONFIG_FUNCTION_TRACER
  72. /*
  73. * Prologue for the preempt and irqs off function tracers.
  74. *
  75. * Returns 1 if it is OK to continue, and data->disabled is
  76. * incremented.
  77. * 0 if the trace is to be ignored, and data->disabled
  78. * is kept the same.
  79. *
  80. * Note, this function is also used outside this ifdef but
  81. * inside the #ifdef of the function graph tracer below.
  82. * This is OK, since the function graph tracer is
  83. * dependent on the function tracer.
  84. */
  85. static int func_prolog_dec(struct trace_array *tr,
  86. struct trace_array_cpu **data,
  87. unsigned long *flags)
  88. {
  89. long disabled;
  90. int cpu;
  91. /*
  92. * Does not matter if we preempt. We test the flags
  93. * afterward, to see if irqs are disabled or not.
  94. * If we preempt and get a false positive, the flags
  95. * test will fail.
  96. */
  97. cpu = raw_smp_processor_id();
  98. if (likely(!per_cpu(tracing_cpu, cpu)))
  99. return 0;
  100. local_save_flags(*flags);
  101. /* slight chance to get a false positive on tracing_cpu */
  102. if (!irqs_disabled_flags(*flags))
  103. return 0;
  104. *data = per_cpu_ptr(tr->trace_buffer.data, cpu);
  105. disabled = atomic_inc_return(&(*data)->disabled);
  106. if (likely(disabled == 1))
  107. return 1;
  108. atomic_dec(&(*data)->disabled);
  109. return 0;
  110. }
  111. /*
  112. * irqsoff uses its own tracer function to keep the overhead down:
  113. */
  114. static void
  115. irqsoff_tracer_call(unsigned long ip, unsigned long parent_ip,
  116. struct ftrace_ops *op, struct pt_regs *pt_regs)
  117. {
  118. struct trace_array *tr = irqsoff_trace;
  119. struct trace_array_cpu *data;
  120. unsigned long flags;
  121. if (!func_prolog_dec(tr, &data, &flags))
  122. return;
  123. trace_function(tr, ip, parent_ip, flags, preempt_count());
  124. atomic_dec(&data->disabled);
  125. }
  126. #endif /* CONFIG_FUNCTION_TRACER */
  127. #ifdef CONFIG_FUNCTION_GRAPH_TRACER
  128. static int
  129. irqsoff_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set)
  130. {
  131. int cpu;
  132. if (!(bit & TRACE_DISPLAY_GRAPH))
  133. return -EINVAL;
  134. if (!(is_graph() ^ set))
  135. return 0;
  136. stop_irqsoff_tracer(irqsoff_trace, !set);
  137. for_each_possible_cpu(cpu)
  138. per_cpu(tracing_cpu, cpu) = 0;
  139. tr->max_latency = 0;
  140. tracing_reset_online_cpus(&irqsoff_trace->trace_buffer);
  141. return start_irqsoff_tracer(irqsoff_trace, set);
  142. }
  143. static int irqsoff_graph_entry(struct ftrace_graph_ent *trace)
  144. {
  145. struct trace_array *tr = irqsoff_trace;
  146. struct trace_array_cpu *data;
  147. unsigned long flags;
  148. int ret;
  149. int pc;
  150. if (!func_prolog_dec(tr, &data, &flags))
  151. return 0;
  152. pc = preempt_count();
  153. ret = __trace_graph_entry(tr, trace, flags, pc);
  154. atomic_dec(&data->disabled);
  155. return ret;
  156. }
  157. static void irqsoff_graph_return(struct ftrace_graph_ret *trace)
  158. {
  159. struct trace_array *tr = irqsoff_trace;
  160. struct trace_array_cpu *data;
  161. unsigned long flags;
  162. int pc;
  163. if (!func_prolog_dec(tr, &data, &flags))
  164. return;
  165. pc = preempt_count();
  166. __trace_graph_return(tr, trace, flags, pc);
  167. atomic_dec(&data->disabled);
  168. }
  169. static void irqsoff_trace_open(struct trace_iterator *iter)
  170. {
  171. if (is_graph())
  172. graph_trace_open(iter);
  173. }
  174. static void irqsoff_trace_close(struct trace_iterator *iter)
  175. {
  176. if (iter->private)
  177. graph_trace_close(iter);
  178. }
  179. #define GRAPH_TRACER_FLAGS (TRACE_GRAPH_PRINT_CPU | \
  180. TRACE_GRAPH_PRINT_PROC | \
  181. TRACE_GRAPH_PRINT_ABS_TIME | \
  182. TRACE_GRAPH_PRINT_DURATION)
  183. static enum print_line_t irqsoff_print_line(struct trace_iterator *iter)
  184. {
  185. /*
  186. * In graph mode call the graph tracer output function,
  187. * otherwise go with the TRACE_FN event handler
  188. */
  189. if (is_graph())
  190. return print_graph_function_flags(iter, GRAPH_TRACER_FLAGS);
  191. return TRACE_TYPE_UNHANDLED;
  192. }
  193. static void irqsoff_print_header(struct seq_file *s)
  194. {
  195. if (is_graph())
  196. print_graph_headers_flags(s, GRAPH_TRACER_FLAGS);
  197. else
  198. trace_default_header(s);
  199. }
  200. static void
  201. __trace_function(struct trace_array *tr,
  202. unsigned long ip, unsigned long parent_ip,
  203. unsigned long flags, int pc)
  204. {
  205. if (is_graph())
  206. trace_graph_function(tr, ip, parent_ip, flags, pc);
  207. else
  208. trace_function(tr, ip, parent_ip, flags, pc);
  209. }
  210. #else
  211. #define __trace_function trace_function
  212. static int
  213. irqsoff_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set)
  214. {
  215. return -EINVAL;
  216. }
  217. static int irqsoff_graph_entry(struct ftrace_graph_ent *trace)
  218. {
  219. return -1;
  220. }
  221. static enum print_line_t irqsoff_print_line(struct trace_iterator *iter)
  222. {
  223. return TRACE_TYPE_UNHANDLED;
  224. }
  225. static void irqsoff_graph_return(struct ftrace_graph_ret *trace) { }
  226. static void irqsoff_trace_open(struct trace_iterator *iter) { }
  227. static void irqsoff_trace_close(struct trace_iterator *iter) { }
  228. #ifdef CONFIG_FUNCTION_TRACER
  229. static void irqsoff_print_header(struct seq_file *s)
  230. {
  231. trace_default_header(s);
  232. }
  233. #else
  234. static void irqsoff_print_header(struct seq_file *s)
  235. {
  236. trace_latency_header(s);
  237. }
  238. #endif /* CONFIG_FUNCTION_TRACER */
  239. #endif /* CONFIG_FUNCTION_GRAPH_TRACER */
  240. /*
  241. * Should this new latency be reported/recorded?
  242. */
  243. static int report_latency(struct trace_array *tr, cycle_t delta)
  244. {
  245. if (tracing_thresh) {
  246. if (delta < tracing_thresh)
  247. return 0;
  248. } else {
  249. if (delta <= tr->max_latency)
  250. return 0;
  251. }
  252. return 1;
  253. }
  254. static void
  255. check_critical_timing(struct trace_array *tr,
  256. struct trace_array_cpu *data,
  257. unsigned long parent_ip,
  258. int cpu)
  259. {
  260. cycle_t T0, T1, delta;
  261. unsigned long flags;
  262. int pc;
  263. T0 = data->preempt_timestamp;
  264. T1 = ftrace_now(cpu);
  265. delta = T1-T0;
  266. local_save_flags(flags);
  267. pc = preempt_count();
  268. if (!report_latency(tr, delta))
  269. goto out;
  270. raw_spin_lock_irqsave(&max_trace_lock, flags);
  271. /* check if we are still the max latency */
  272. if (!report_latency(tr, delta))
  273. goto out_unlock;
  274. __trace_function(tr, CALLER_ADDR0, parent_ip, flags, pc);
  275. /* Skip 5 functions to get to the irq/preempt enable function */
  276. __trace_stack(tr, flags, 5, pc);
  277. if (data->critical_sequence != max_sequence)
  278. goto out_unlock;
  279. data->critical_end = parent_ip;
  280. if (likely(!is_tracing_stopped())) {
  281. tr->max_latency = delta;
  282. update_max_tr_single(tr, current, cpu);
  283. }
  284. max_sequence++;
  285. out_unlock:
  286. raw_spin_unlock_irqrestore(&max_trace_lock, flags);
  287. out:
  288. data->critical_sequence = max_sequence;
  289. data->preempt_timestamp = ftrace_now(cpu);
  290. __trace_function(tr, CALLER_ADDR0, parent_ip, flags, pc);
  291. }
  292. static inline void
  293. start_critical_timing(unsigned long ip, unsigned long parent_ip)
  294. {
  295. int cpu;
  296. struct trace_array *tr = irqsoff_trace;
  297. struct trace_array_cpu *data;
  298. unsigned long flags;
  299. if (!tracer_enabled || !tracing_is_enabled())
  300. return;
  301. cpu = raw_smp_processor_id();
  302. if (per_cpu(tracing_cpu, cpu))
  303. return;
  304. data = per_cpu_ptr(tr->trace_buffer.data, cpu);
  305. if (unlikely(!data) || atomic_read(&data->disabled))
  306. return;
  307. atomic_inc(&data->disabled);
  308. data->critical_sequence = max_sequence;
  309. data->preempt_timestamp = ftrace_now(cpu);
  310. data->critical_start = parent_ip ? : ip;
  311. local_save_flags(flags);
  312. __trace_function(tr, ip, parent_ip, flags, preempt_count());
  313. per_cpu(tracing_cpu, cpu) = 1;
  314. atomic_dec(&data->disabled);
  315. }
  316. static inline void
  317. stop_critical_timing(unsigned long ip, unsigned long parent_ip)
  318. {
  319. int cpu;
  320. struct trace_array *tr = irqsoff_trace;
  321. struct trace_array_cpu *data;
  322. unsigned long flags;
  323. cpu = raw_smp_processor_id();
  324. /* Always clear the tracing cpu on stopping the trace */
  325. if (unlikely(per_cpu(tracing_cpu, cpu)))
  326. per_cpu(tracing_cpu, cpu) = 0;
  327. else
  328. return;
  329. if (!tracer_enabled || !tracing_is_enabled())
  330. return;
  331. data = per_cpu_ptr(tr->trace_buffer.data, cpu);
  332. if (unlikely(!data) ||
  333. !data->critical_start || atomic_read(&data->disabled))
  334. return;
  335. atomic_inc(&data->disabled);
  336. local_save_flags(flags);
  337. __trace_function(tr, ip, parent_ip, flags, preempt_count());
  338. check_critical_timing(tr, data, parent_ip ? : ip, cpu);
  339. data->critical_start = 0;
  340. atomic_dec(&data->disabled);
  341. }
  342. /* start and stop critical timings used to for stoppage (in idle) */
  343. void start_critical_timings(void)
  344. {
  345. if (preempt_trace() || irq_trace())
  346. start_critical_timing(CALLER_ADDR0, CALLER_ADDR1);
  347. }
  348. EXPORT_SYMBOL_GPL(start_critical_timings);
  349. void stop_critical_timings(void)
  350. {
  351. if (preempt_trace() || irq_trace())
  352. stop_critical_timing(CALLER_ADDR0, CALLER_ADDR1);
  353. }
  354. EXPORT_SYMBOL_GPL(stop_critical_timings);
  355. #ifdef CONFIG_IRQSOFF_TRACER
  356. #ifdef CONFIG_PROVE_LOCKING
  357. void time_hardirqs_on(unsigned long a0, unsigned long a1)
  358. {
  359. if (!preempt_trace() && irq_trace())
  360. stop_critical_timing(a0, a1);
  361. }
  362. void time_hardirqs_off(unsigned long a0, unsigned long a1)
  363. {
  364. if (!preempt_trace() && irq_trace())
  365. start_critical_timing(a0, a1);
  366. }
  367. #else /* !CONFIG_PROVE_LOCKING */
  368. /*
  369. * Stubs:
  370. */
  371. void trace_softirqs_on(unsigned long ip)
  372. {
  373. }
  374. void trace_softirqs_off(unsigned long ip)
  375. {
  376. }
  377. inline void print_irqtrace_events(struct task_struct *curr)
  378. {
  379. }
  380. /*
  381. * We are only interested in hardirq on/off events:
  382. */
  383. void trace_hardirqs_on(void)
  384. {
  385. if (!preempt_trace() && irq_trace())
  386. stop_critical_timing(CALLER_ADDR0, CALLER_ADDR1);
  387. }
  388. EXPORT_SYMBOL(trace_hardirqs_on);
  389. void trace_hardirqs_off(void)
  390. {
  391. if (!preempt_trace() && irq_trace())
  392. start_critical_timing(CALLER_ADDR0, CALLER_ADDR1);
  393. }
  394. EXPORT_SYMBOL(trace_hardirqs_off);
  395. __visible void trace_hardirqs_on_caller(unsigned long caller_addr)
  396. {
  397. if (!preempt_trace() && irq_trace())
  398. stop_critical_timing(CALLER_ADDR0, caller_addr);
  399. }
  400. EXPORT_SYMBOL(trace_hardirqs_on_caller);
  401. __visible void trace_hardirqs_off_caller(unsigned long caller_addr)
  402. {
  403. if (!preempt_trace() && irq_trace())
  404. start_critical_timing(CALLER_ADDR0, caller_addr);
  405. }
  406. EXPORT_SYMBOL(trace_hardirqs_off_caller);
  407. #endif /* CONFIG_PROVE_LOCKING */
  408. #endif /* CONFIG_IRQSOFF_TRACER */
  409. #ifdef CONFIG_PREEMPT_TRACER
  410. void trace_preempt_on(unsigned long a0, unsigned long a1)
  411. {
  412. if (preempt_trace() && !irq_trace())
  413. stop_critical_timing(a0, a1);
  414. }
  415. void trace_preempt_off(unsigned long a0, unsigned long a1)
  416. {
  417. if (preempt_trace() && !irq_trace())
  418. start_critical_timing(a0, a1);
  419. }
  420. #endif /* CONFIG_PREEMPT_TRACER */
  421. static int register_irqsoff_function(struct trace_array *tr, int graph, int set)
  422. {
  423. int ret;
  424. /* 'set' is set if TRACE_ITER_FUNCTION is about to be set */
  425. if (function_enabled || (!set && !(trace_flags & TRACE_ITER_FUNCTION)))
  426. return 0;
  427. if (graph)
  428. ret = register_ftrace_graph(&irqsoff_graph_return,
  429. &irqsoff_graph_entry);
  430. else
  431. ret = register_ftrace_function(tr->ops);
  432. if (!ret)
  433. function_enabled = true;
  434. return ret;
  435. }
  436. static void unregister_irqsoff_function(struct trace_array *tr, int graph)
  437. {
  438. if (!function_enabled)
  439. return;
  440. if (graph)
  441. unregister_ftrace_graph();
  442. else
  443. unregister_ftrace_function(tr->ops);
  444. function_enabled = false;
  445. }
  446. static void irqsoff_function_set(struct trace_array *tr, int set)
  447. {
  448. if (set)
  449. register_irqsoff_function(tr, is_graph(), 1);
  450. else
  451. unregister_irqsoff_function(tr, is_graph());
  452. }
  453. static int irqsoff_flag_changed(struct trace_array *tr, u32 mask, int set)
  454. {
  455. struct tracer *tracer = tr->current_trace;
  456. if (mask & TRACE_ITER_FUNCTION)
  457. irqsoff_function_set(tr, set);
  458. return trace_keep_overwrite(tracer, mask, set);
  459. }
  460. static int start_irqsoff_tracer(struct trace_array *tr, int graph)
  461. {
  462. int ret;
  463. ret = register_irqsoff_function(tr, graph, 0);
  464. if (!ret && tracing_is_enabled())
  465. tracer_enabled = 1;
  466. else
  467. tracer_enabled = 0;
  468. return ret;
  469. }
  470. static void stop_irqsoff_tracer(struct trace_array *tr, int graph)
  471. {
  472. tracer_enabled = 0;
  473. unregister_irqsoff_function(tr, graph);
  474. }
  475. static bool irqsoff_busy;
  476. static int __irqsoff_tracer_init(struct trace_array *tr)
  477. {
  478. if (irqsoff_busy)
  479. return -EBUSY;
  480. save_flags = trace_flags;
  481. /* non overwrite screws up the latency tracers */
  482. set_tracer_flag(tr, TRACE_ITER_OVERWRITE, 1);
  483. set_tracer_flag(tr, TRACE_ITER_LATENCY_FMT, 1);
  484. tr->max_latency = 0;
  485. irqsoff_trace = tr;
  486. /* make sure that the tracer is visible */
  487. smp_wmb();
  488. tracing_reset_online_cpus(&tr->trace_buffer);
  489. ftrace_init_array_ops(tr, irqsoff_tracer_call);
  490. /* Only toplevel instance supports graph tracing */
  491. if (start_irqsoff_tracer(tr, (tr->flags & TRACE_ARRAY_FL_GLOBAL &&
  492. is_graph())))
  493. printk(KERN_ERR "failed to start irqsoff tracer\n");
  494. irqsoff_busy = true;
  495. return 0;
  496. }
  497. static void irqsoff_tracer_reset(struct trace_array *tr)
  498. {
  499. int lat_flag = save_flags & TRACE_ITER_LATENCY_FMT;
  500. int overwrite_flag = save_flags & TRACE_ITER_OVERWRITE;
  501. stop_irqsoff_tracer(tr, is_graph());
  502. set_tracer_flag(tr, TRACE_ITER_LATENCY_FMT, lat_flag);
  503. set_tracer_flag(tr, TRACE_ITER_OVERWRITE, overwrite_flag);
  504. ftrace_reset_array_ops(tr);
  505. irqsoff_busy = false;
  506. }
  507. static void irqsoff_tracer_start(struct trace_array *tr)
  508. {
  509. tracer_enabled = 1;
  510. }
  511. static void irqsoff_tracer_stop(struct trace_array *tr)
  512. {
  513. tracer_enabled = 0;
  514. }
  515. #ifdef CONFIG_IRQSOFF_TRACER
  516. static int irqsoff_tracer_init(struct trace_array *tr)
  517. {
  518. trace_type = TRACER_IRQS_OFF;
  519. return __irqsoff_tracer_init(tr);
  520. }
  521. static struct tracer irqsoff_tracer __read_mostly =
  522. {
  523. .name = "irqsoff",
  524. .init = irqsoff_tracer_init,
  525. .reset = irqsoff_tracer_reset,
  526. .start = irqsoff_tracer_start,
  527. .stop = irqsoff_tracer_stop,
  528. .print_max = true,
  529. .print_header = irqsoff_print_header,
  530. .print_line = irqsoff_print_line,
  531. .flags = &tracer_flags,
  532. .set_flag = irqsoff_set_flag,
  533. .flag_changed = irqsoff_flag_changed,
  534. #ifdef CONFIG_FTRACE_SELFTEST
  535. .selftest = trace_selftest_startup_irqsoff,
  536. #endif
  537. .open = irqsoff_trace_open,
  538. .close = irqsoff_trace_close,
  539. .allow_instances = true,
  540. .use_max_tr = true,
  541. };
  542. # define register_irqsoff(trace) register_tracer(&trace)
  543. #else
  544. # define register_irqsoff(trace) do { } while (0)
  545. #endif
  546. #ifdef CONFIG_PREEMPT_TRACER
  547. static int preemptoff_tracer_init(struct trace_array *tr)
  548. {
  549. trace_type = TRACER_PREEMPT_OFF;
  550. return __irqsoff_tracer_init(tr);
  551. }
  552. static struct tracer preemptoff_tracer __read_mostly =
  553. {
  554. .name = "preemptoff",
  555. .init = preemptoff_tracer_init,
  556. .reset = irqsoff_tracer_reset,
  557. .start = irqsoff_tracer_start,
  558. .stop = irqsoff_tracer_stop,
  559. .print_max = true,
  560. .print_header = irqsoff_print_header,
  561. .print_line = irqsoff_print_line,
  562. .flags = &tracer_flags,
  563. .set_flag = irqsoff_set_flag,
  564. .flag_changed = irqsoff_flag_changed,
  565. #ifdef CONFIG_FTRACE_SELFTEST
  566. .selftest = trace_selftest_startup_preemptoff,
  567. #endif
  568. .open = irqsoff_trace_open,
  569. .close = irqsoff_trace_close,
  570. .allow_instances = true,
  571. .use_max_tr = true,
  572. };
  573. # define register_preemptoff(trace) register_tracer(&trace)
  574. #else
  575. # define register_preemptoff(trace) do { } while (0)
  576. #endif
  577. #if defined(CONFIG_IRQSOFF_TRACER) && \
  578. defined(CONFIG_PREEMPT_TRACER)
  579. static int preemptirqsoff_tracer_init(struct trace_array *tr)
  580. {
  581. trace_type = TRACER_IRQS_OFF | TRACER_PREEMPT_OFF;
  582. return __irqsoff_tracer_init(tr);
  583. }
  584. static struct tracer preemptirqsoff_tracer __read_mostly =
  585. {
  586. .name = "preemptirqsoff",
  587. .init = preemptirqsoff_tracer_init,
  588. .reset = irqsoff_tracer_reset,
  589. .start = irqsoff_tracer_start,
  590. .stop = irqsoff_tracer_stop,
  591. .print_max = true,
  592. .print_header = irqsoff_print_header,
  593. .print_line = irqsoff_print_line,
  594. .flags = &tracer_flags,
  595. .set_flag = irqsoff_set_flag,
  596. .flag_changed = irqsoff_flag_changed,
  597. #ifdef CONFIG_FTRACE_SELFTEST
  598. .selftest = trace_selftest_startup_preemptirqsoff,
  599. #endif
  600. .open = irqsoff_trace_open,
  601. .close = irqsoff_trace_close,
  602. .allow_instances = true,
  603. .use_max_tr = true,
  604. };
  605. # define register_preemptirqsoff(trace) register_tracer(&trace)
  606. #else
  607. # define register_preemptirqsoff(trace) do { } while (0)
  608. #endif
  609. __init static int init_irqsoff_tracer(void)
  610. {
  611. register_irqsoff(irqsoff_tracer);
  612. register_preemptoff(preemptoff_tracer);
  613. register_preemptirqsoff(preemptirqsoff_tracer);
  614. return 0;
  615. }
  616. core_initcall(init_irqsoff_tracer);