~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/lib/test_objpool.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 
  3 /*
  4  * Test module for lockless object pool
  5  *
  6  * Copyright: wuqiang.matt@bytedance.com
  7  */
  8 
  9 #include <linux/errno.h>
 10 #include <linux/module.h>
 11 #include <linux/moduleparam.h>
 12 #include <linux/completion.h>
 13 #include <linux/kthread.h>
 14 #include <linux/slab.h>
 15 #include <linux/vmalloc.h>
 16 #include <linux/delay.h>
 17 #include <linux/hrtimer.h>
 18 #include <linux/objpool.h>
 19 
 20 #define OT_NR_MAX_BULK (16)
 21 
 22 /* memory usage */
 23 struct ot_mem_stat {
 24         atomic_long_t alloc;
 25         atomic_long_t free;
 26 };
 27 
 28 /* object allocation results */
 29 struct ot_obj_stat {
 30         unsigned long nhits;
 31         unsigned long nmiss;
 32 };
 33 
 34 /* control & results per testcase */
 35 struct ot_data {
 36         struct rw_semaphore start;
 37         struct completion wait;
 38         struct completion rcu;
 39         atomic_t nthreads ____cacheline_aligned_in_smp;
 40         atomic_t stop ____cacheline_aligned_in_smp;
 41         struct ot_mem_stat kmalloc;
 42         struct ot_mem_stat vmalloc;
 43         struct ot_obj_stat objects;
 44         u64    duration;
 45 };
 46 
 47 /* testcase */
 48 struct ot_test {
 49         int async; /* synchronous or asynchronous */
 50         int mode; /* only mode 0 supported */
 51         int objsz; /* object size */
 52         int duration; /* ms */
 53         int delay; /* ms */
 54         int bulk_normal;
 55         int bulk_irq;
 56         unsigned long hrtimer; /* ms */
 57         const char *name;
 58         struct ot_data data;
 59 };
 60 
 61 /* per-cpu worker */
 62 struct ot_item {
 63         struct objpool_head *pool; /* pool head */
 64         struct ot_test *test; /* test parameters */
 65 
 66         void (*worker)(struct ot_item *item, int irq);
 67 
 68         /* hrtimer control */
 69         ktime_t hrtcycle;
 70         struct hrtimer hrtimer;
 71 
 72         int bulk[2]; /* for thread and irq */
 73         int delay;
 74         u32 niters;
 75 
 76         /* summary per thread */
 77         struct ot_obj_stat stat[2]; /* thread and irq */
 78         u64 duration;
 79 };
 80 
 81 /*
 82  * memory leakage checking
 83  */
 84 
 85 static void *ot_kzalloc(struct ot_test *test, long size)
 86 {
 87         void *ptr = kzalloc(size, GFP_KERNEL);
 88 
 89         if (ptr)
 90                 atomic_long_add(size, &test->data.kmalloc.alloc);
 91         return ptr;
 92 }
 93 
 94 static void ot_kfree(struct ot_test *test, void *ptr, long size)
 95 {
 96         if (!ptr)
 97                 return;
 98         atomic_long_add(size, &test->data.kmalloc.free);
 99         kfree(ptr);
100 }
101 
102 static void ot_mem_report(struct ot_test *test)
103 {
104         long alloc, free;
105 
106         pr_info("memory allocation summary for %s\n", test->name);
107 
108         alloc = atomic_long_read(&test->data.kmalloc.alloc);
109         free = atomic_long_read(&test->data.kmalloc.free);
110         pr_info("  kmalloc: %lu - %lu = %lu\n", alloc, free, alloc - free);
111 
112         alloc = atomic_long_read(&test->data.vmalloc.alloc);
113         free = atomic_long_read(&test->data.vmalloc.free);
114         pr_info("  vmalloc: %lu - %lu = %lu\n", alloc, free, alloc - free);
115 }
116 
117 /* user object instance */
118 struct ot_node {
119         void *owner;
120         unsigned long data;
121         unsigned long refs;
122         unsigned long payload[32];
123 };
124 
125 /* user objpool manager */
126 struct ot_context {
127         struct objpool_head pool; /* objpool head */
128         struct ot_test *test; /* test parameters */
129         void *ptr; /* user pool buffer */
130         unsigned long size; /* buffer size */
131         struct rcu_head rcu;
132 };
133 
134 static DEFINE_PER_CPU(struct ot_item, ot_pcup_items);
135 
136 static int ot_init_data(struct ot_data *data)
137 {
138         memset(data, 0, sizeof(*data));
139         init_rwsem(&data->start);
140         init_completion(&data->wait);
141         init_completion(&data->rcu);
142         atomic_set(&data->nthreads, 1);
143 
144         return 0;
145 }
146 
147 static int ot_init_node(void *nod, void *context)
148 {
149         struct ot_context *sop = context;
150         struct ot_node *on = nod;
151 
152         on->owner = &sop->pool;
153         return 0;
154 }
155 
156 static enum hrtimer_restart ot_hrtimer_handler(struct hrtimer *hrt)
157 {
158         struct ot_item *item = container_of(hrt, struct ot_item, hrtimer);
159         struct ot_test *test = item->test;
160 
161         if (atomic_read_acquire(&test->data.stop))
162                 return HRTIMER_NORESTART;
163 
164         /* do bulk-testings for objects pop/push */
165         item->worker(item, 1);
166 
167         hrtimer_forward(hrt, hrt->base->get_time(), item->hrtcycle);
168         return HRTIMER_RESTART;
169 }
170 
171 static void ot_start_hrtimer(struct ot_item *item)
172 {
173         if (!item->test->hrtimer)
174                 return;
175         hrtimer_start(&item->hrtimer, item->hrtcycle, HRTIMER_MODE_REL);
176 }
177 
178 static void ot_stop_hrtimer(struct ot_item *item)
179 {
180         if (!item->test->hrtimer)
181                 return;
182         hrtimer_cancel(&item->hrtimer);
183 }
184 
185 static int ot_init_hrtimer(struct ot_item *item, unsigned long hrtimer)
186 {
187         struct hrtimer *hrt = &item->hrtimer;
188 
189         if (!hrtimer)
190                 return -ENOENT;
191 
192         item->hrtcycle = ktime_set(0, hrtimer * 1000000UL);
193         hrtimer_init(hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
194         hrt->function = ot_hrtimer_handler;
195         return 0;
196 }
197 
198 static int ot_init_cpu_item(struct ot_item *item,
199                         struct ot_test *test,
200                         struct objpool_head *pool,
201                         void (*worker)(struct ot_item *, int))
202 {
203         memset(item, 0, sizeof(*item));
204         item->pool = pool;
205         item->test = test;
206         item->worker = worker;
207 
208         item->bulk[0] = test->bulk_normal;
209         item->bulk[1] = test->bulk_irq;
210         item->delay = test->delay;
211 
212         /* initialize hrtimer */
213         ot_init_hrtimer(item, item->test->hrtimer);
214         return 0;
215 }
216 
217 static int ot_thread_worker(void *arg)
218 {
219         struct ot_item *item = arg;
220         struct ot_test *test = item->test;
221         ktime_t start;
222 
223         atomic_inc(&test->data.nthreads);
224         down_read(&test->data.start);
225         up_read(&test->data.start);
226         start = ktime_get();
227         ot_start_hrtimer(item);
228         do {
229                 if (atomic_read_acquire(&test->data.stop))
230                         break;
231                 /* do bulk-testings for objects pop/push */
232                 item->worker(item, 0);
233         } while (!kthread_should_stop());
234         ot_stop_hrtimer(item);
235         item->duration = (u64) ktime_us_delta(ktime_get(), start);
236         if (atomic_dec_and_test(&test->data.nthreads))
237                 complete(&test->data.wait);
238 
239         return 0;
240 }
241 
242 static void ot_perf_report(struct ot_test *test, u64 duration)
243 {
244         struct ot_obj_stat total, normal = {0}, irq = {0};
245         int cpu, nthreads = 0;
246 
247         pr_info("\n");
248         pr_info("Testing summary for %s\n", test->name);
249 
250         for_each_possible_cpu(cpu) {
251                 struct ot_item *item = per_cpu_ptr(&ot_pcup_items, cpu);
252                 if (!item->duration)
253                         continue;
254                 normal.nhits += item->stat[0].nhits;
255                 normal.nmiss += item->stat[0].nmiss;
256                 irq.nhits += item->stat[1].nhits;
257                 irq.nmiss += item->stat[1].nmiss;
258                 pr_info("CPU: %d  duration: %lluus\n", cpu, item->duration);
259                 pr_info("\tthread:\t%16lu hits \t%16lu miss\n",
260                         item->stat[0].nhits, item->stat[0].nmiss);
261                 pr_info("\tirq:   \t%16lu hits \t%16lu miss\n",
262                         item->stat[1].nhits, item->stat[1].nmiss);
263                 pr_info("\ttotal: \t%16lu hits \t%16lu miss\n",
264                         item->stat[0].nhits + item->stat[1].nhits,
265                         item->stat[0].nmiss + item->stat[1].nmiss);
266                 nthreads++;
267         }
268 
269         total.nhits = normal.nhits + irq.nhits;
270         total.nmiss = normal.nmiss + irq.nmiss;
271 
272         pr_info("ALL: \tnthreads: %d  duration: %lluus\n", nthreads, duration);
273         pr_info("SUM: \t%16lu hits \t%16lu miss\n",
274                 total.nhits, total.nmiss);
275 
276         test->data.objects = total;
277         test->data.duration = duration;
278 }
279 
280 /*
281  * synchronous test cases for objpool manipulation
282  */
283 
284 /* objpool manipulation for synchronous mode (percpu objpool) */
285 static struct ot_context *ot_init_sync_m0(struct ot_test *test)
286 {
287         struct ot_context *sop = NULL;
288         int max = num_possible_cpus() << 3;
289         gfp_t gfp = GFP_KERNEL;
290 
291         sop = (struct ot_context *)ot_kzalloc(test, sizeof(*sop));
292         if (!sop)
293                 return NULL;
294         sop->test = test;
295         if (test->objsz < 512)
296                 gfp = GFP_ATOMIC;
297 
298         if (objpool_init(&sop->pool, max, test->objsz,
299                          gfp, sop, ot_init_node, NULL)) {
300                 ot_kfree(test, sop, sizeof(*sop));
301                 return NULL;
302         }
303         WARN_ON(max != sop->pool.nr_objs);
304 
305         return sop;
306 }
307 
308 static void ot_fini_sync(struct ot_context *sop)
309 {
310         objpool_fini(&sop->pool);
311         ot_kfree(sop->test, sop, sizeof(*sop));
312 }
313 
314 static struct {
315         struct ot_context * (*init)(struct ot_test *oc);
316         void (*fini)(struct ot_context *sop);
317 } g_ot_sync_ops[] = {
318         {.init = ot_init_sync_m0, .fini = ot_fini_sync},
319 };
320 
321 /*
322  * synchronous test cases: performance mode
323  */
324 
325 static void ot_bulk_sync(struct ot_item *item, int irq)
326 {
327         struct ot_node *nods[OT_NR_MAX_BULK];
328         int i;
329 
330         for (i = 0; i < item->bulk[irq]; i++)
331                 nods[i] = objpool_pop(item->pool);
332 
333         if (!irq && (item->delay || !(++(item->niters) & 0x7FFF)))
334                 msleep(item->delay);
335 
336         while (i-- > 0) {
337                 struct ot_node *on = nods[i];
338                 if (on) {
339                         on->refs++;
340                         objpool_push(on, item->pool);
341                         item->stat[irq].nhits++;
342                 } else {
343                         item->stat[irq].nmiss++;
344                 }
345         }
346 }
347 
348 static int ot_start_sync(struct ot_test *test)
349 {
350         struct ot_context *sop;
351         ktime_t start;
352         u64 duration;
353         unsigned long timeout;
354         int cpu;
355 
356         /* initialize objpool for syncrhonous testcase */
357         sop = g_ot_sync_ops[test->mode].init(test);
358         if (!sop)
359                 return -ENOMEM;
360 
361         /* grab rwsem to block testing threads */
362         down_write(&test->data.start);
363 
364         for_each_possible_cpu(cpu) {
365                 struct ot_item *item = per_cpu_ptr(&ot_pcup_items, cpu);
366                 struct task_struct *work;
367 
368                 ot_init_cpu_item(item, test, &sop->pool, ot_bulk_sync);
369 
370                 /* skip offline cpus */
371                 if (!cpu_online(cpu))
372                         continue;
373 
374                 work = kthread_create_on_node(ot_thread_worker, item,
375                                 cpu_to_node(cpu), "ot_worker_%d", cpu);
376                 if (IS_ERR(work)) {
377                         pr_err("failed to create thread for cpu %d\n", cpu);
378                 } else {
379                         kthread_bind(work, cpu);
380                         wake_up_process(work);
381                 }
382         }
383 
384         /* wait a while to make sure all threads waiting at start line */
385         msleep(20);
386 
387         /* in case no threads were created: memory insufficient ? */
388         if (atomic_dec_and_test(&test->data.nthreads))
389                 complete(&test->data.wait);
390 
391         // sched_set_fifo_low(current);
392 
393         /* start objpool testing threads */
394         start = ktime_get();
395         up_write(&test->data.start);
396 
397         /* yeild cpu to worker threads for duration ms */
398         timeout = msecs_to_jiffies(test->duration);
399         schedule_timeout_interruptible(timeout);
400 
401         /* tell workers threads to quit */
402         atomic_set_release(&test->data.stop, 1);
403 
404         /* wait all workers threads finish and quit */
405         wait_for_completion(&test->data.wait);
406         duration = (u64) ktime_us_delta(ktime_get(), start);
407 
408         /* cleanup objpool */
409         g_ot_sync_ops[test->mode].fini(sop);
410 
411         /* report testing summary and performance results */
412         ot_perf_report(test, duration);
413 
414         /* report memory allocation summary */
415         ot_mem_report(test);
416 
417         return 0;
418 }
419 
420 /*
421  * asynchronous test cases: pool lifecycle controlled by refcount
422  */
423 
424 static void ot_fini_async_rcu(struct rcu_head *rcu)
425 {
426         struct ot_context *sop = container_of(rcu, struct ot_context, rcu);
427         struct ot_test *test = sop->test;
428 
429         /* here all cpus are aware of the stop event: test->data.stop = 1 */
430         WARN_ON(!atomic_read_acquire(&test->data.stop));
431 
432         objpool_fini(&sop->pool);
433         complete(&test->data.rcu);
434 }
435 
436 static void ot_fini_async(struct ot_context *sop)
437 {
438         /* make sure the stop event is acknowledged by all cores */
439         call_rcu(&sop->rcu, ot_fini_async_rcu);
440 }
441 
442 static int ot_objpool_release(struct objpool_head *head, void *context)
443 {
444         struct ot_context *sop = context;
445 
446         WARN_ON(!head || !sop || head != &sop->pool);
447 
448         /* do context cleaning if needed */
449         if (sop)
450                 ot_kfree(sop->test, sop, sizeof(*sop));
451 
452         return 0;
453 }
454 
455 static struct ot_context *ot_init_async_m0(struct ot_test *test)
456 {
457         struct ot_context *sop = NULL;
458         int max = num_possible_cpus() << 3;
459         gfp_t gfp = GFP_KERNEL;
460 
461         sop = (struct ot_context *)ot_kzalloc(test, sizeof(*sop));
462         if (!sop)
463                 return NULL;
464         sop->test = test;
465         if (test->objsz < 512)
466                 gfp = GFP_ATOMIC;
467 
468         if (objpool_init(&sop->pool, max, test->objsz, gfp, sop,
469                          ot_init_node, ot_objpool_release)) {
470                 ot_kfree(test, sop, sizeof(*sop));
471                 return NULL;
472         }
473         WARN_ON(max != sop->pool.nr_objs);
474 
475         return sop;
476 }
477 
478 static struct {
479         struct ot_context * (*init)(struct ot_test *oc);
480         void (*fini)(struct ot_context *sop);
481 } g_ot_async_ops[] = {
482         {.init = ot_init_async_m0, .fini = ot_fini_async},
483 };
484 
485 static void ot_nod_recycle(struct ot_node *on, struct objpool_head *pool,
486                         int release)
487 {
488         struct ot_context *sop;
489 
490         on->refs++;
491 
492         if (!release) {
493                 /* push object back to opjpool for reuse */
494                 objpool_push(on, pool);
495                 return;
496         }
497 
498         sop = container_of(pool, struct ot_context, pool);
499         WARN_ON(sop != pool->context);
500 
501         /* unref objpool with nod removed forever */
502         objpool_drop(on, pool);
503 }
504 
505 static void ot_bulk_async(struct ot_item *item, int irq)
506 {
507         struct ot_test *test = item->test;
508         struct ot_node *nods[OT_NR_MAX_BULK];
509         int i, stop;
510 
511         for (i = 0; i < item->bulk[irq]; i++)
512                 nods[i] = objpool_pop(item->pool);
513 
514         if (!irq) {
515                 if (item->delay || !(++(item->niters) & 0x7FFF))
516                         msleep(item->delay);
517                 get_cpu();
518         }
519 
520         stop = atomic_read_acquire(&test->data.stop);
521 
522         /* drop all objects and deref objpool */
523         while (i-- > 0) {
524                 struct ot_node *on = nods[i];
525 
526                 if (on) {
527                         on->refs++;
528                         ot_nod_recycle(on, item->pool, stop);
529                         item->stat[irq].nhits++;
530                 } else {
531                         item->stat[irq].nmiss++;
532                 }
533         }
534 
535         if (!irq)
536                 put_cpu();
537 }
538 
539 static int ot_start_async(struct ot_test *test)
540 {
541         struct ot_context *sop;
542         ktime_t start;
543         u64 duration;
544         unsigned long timeout;
545         int cpu;
546 
547         /* initialize objpool for syncrhonous testcase */
548         sop = g_ot_async_ops[test->mode].init(test);
549         if (!sop)
550                 return -ENOMEM;
551 
552         /* grab rwsem to block testing threads */
553         down_write(&test->data.start);
554 
555         for_each_possible_cpu(cpu) {
556                 struct ot_item *item = per_cpu_ptr(&ot_pcup_items, cpu);
557                 struct task_struct *work;
558 
559                 ot_init_cpu_item(item, test, &sop->pool, ot_bulk_async);
560 
561                 /* skip offline cpus */
562                 if (!cpu_online(cpu))
563                         continue;
564 
565                 work = kthread_create_on_node(ot_thread_worker, item,
566                                 cpu_to_node(cpu), "ot_worker_%d", cpu);
567                 if (IS_ERR(work)) {
568                         pr_err("failed to create thread for cpu %d\n", cpu);
569                 } else {
570                         kthread_bind(work, cpu);
571                         wake_up_process(work);
572                 }
573         }
574 
575         /* wait a while to make sure all threads waiting at start line */
576         msleep(20);
577 
578         /* in case no threads were created: memory insufficient ? */
579         if (atomic_dec_and_test(&test->data.nthreads))
580                 complete(&test->data.wait);
581 
582         /* start objpool testing threads */
583         start = ktime_get();
584         up_write(&test->data.start);
585 
586         /* yeild cpu to worker threads for duration ms */
587         timeout = msecs_to_jiffies(test->duration);
588         schedule_timeout_interruptible(timeout);
589 
590         /* tell workers threads to quit */
591         atomic_set_release(&test->data.stop, 1);
592 
593         /* do async-finalization */
594         g_ot_async_ops[test->mode].fini(sop);
595 
596         /* wait all workers threads finish and quit */
597         wait_for_completion(&test->data.wait);
598         duration = (u64) ktime_us_delta(ktime_get(), start);
599 
600         /* assure rcu callback is triggered */
601         wait_for_completion(&test->data.rcu);
602 
603         /*
604          * now we are sure that objpool is finalized either
605          * by rcu callback or by worker threads
606          */
607 
608         /* report testing summary and performance results */
609         ot_perf_report(test, duration);
610 
611         /* report memory allocation summary */
612         ot_mem_report(test);
613 
614         return 0;
615 }
616 
617 /*
618  * predefined testing cases:
619  *   synchronous case / overrun case / async case
620  *
621  * async: synchronous or asynchronous testing
622  * mode: only mode 0 supported
623  * objsz: object size
624  * duration: int, total test time in ms
625  * delay: int, delay (in ms) between each iteration
626  * bulk_normal: int, repeat times for thread worker
627  * bulk_irq: int, repeat times for irq consumer
628  * hrtimer: unsigned long, hrtimer intervnal in ms
629  * name: char *, tag for current test ot_item
630  */
631 
632 #define NODE_COMPACT sizeof(struct ot_node)
633 #define NODE_VMALLOC (512)
634 
635 static struct ot_test g_testcases[] = {
636 
637         /* sync & normal */
638         {0, 0, NODE_COMPACT, 1000, 0,  1,  0,  0, "sync: percpu objpool"},
639         {0, 0, NODE_VMALLOC, 1000, 0,  1,  0,  0, "sync: percpu objpool from vmalloc"},
640 
641         /* sync & hrtimer */
642         {0, 0, NODE_COMPACT, 1000, 0,  1,  1,  4, "sync & hrtimer: percpu objpool"},
643         {0, 0, NODE_VMALLOC, 1000, 0,  1,  1,  4, "sync & hrtimer: percpu objpool from vmalloc"},
644 
645         /* sync & overrun */
646         {0, 0, NODE_COMPACT, 1000, 0, 16,  0,  0, "sync overrun: percpu objpool"},
647         {0, 0, NODE_VMALLOC, 1000, 0, 16,  0,  0, "sync overrun: percpu objpool from vmalloc"},
648 
649         /* async mode */
650         {1, 0, NODE_COMPACT, 1000, 100,  1,  0,  0, "async: percpu objpool"},
651         {1, 0, NODE_VMALLOC, 1000, 100,  1,  0,  0, "async: percpu objpool from vmalloc"},
652 
653         /* async + hrtimer mode */
654         {1, 0, NODE_COMPACT, 1000, 0,  4,  4,  4, "async & hrtimer: percpu objpool"},
655         {1, 0, NODE_VMALLOC, 1000, 0,  4,  4,  4, "async & hrtimer: percpu objpool from vmalloc"},
656 };
657 
658 static int __init ot_mod_init(void)
659 {
660         int i;
661 
662         /* perform testings */
663         for (i = 0; i < ARRAY_SIZE(g_testcases); i++) {
664                 ot_init_data(&g_testcases[i].data);
665                 if (g_testcases[i].async)
666                         ot_start_async(&g_testcases[i]);
667                 else
668                         ot_start_sync(&g_testcases[i]);
669         }
670 
671         /* show tests summary */
672         pr_info("\n");
673         pr_info("Summary of testcases:\n");
674         for (i = 0; i < ARRAY_SIZE(g_testcases); i++) {
675                 pr_info("    duration: %lluus \thits: %10lu \tmiss: %10lu \t%s\n",
676                         g_testcases[i].data.duration, g_testcases[i].data.objects.nhits,
677                         g_testcases[i].data.objects.nmiss, g_testcases[i].name);
678         }
679 
680         return -EAGAIN;
681 }
682 
683 static void __exit ot_mod_exit(void)
684 {
685 }
686 
687 module_init(ot_mod_init);
688 module_exit(ot_mod_exit);
689 
690 MODULE_LICENSE("GPL");

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php