cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ring_buffer_benchmark.c (11058B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * ring buffer tester and benchmark
      4 *
      5 * Copyright (C) 2009 Steven Rostedt <srostedt@redhat.com>
      6 */
      7#include <linux/ring_buffer.h>
      8#include <linux/completion.h>
      9#include <linux/kthread.h>
     10#include <uapi/linux/sched/types.h>
     11#include <linux/module.h>
     12#include <linux/ktime.h>
     13#include <asm/local.h>
     14
     15struct rb_page {
     16	u64		ts;
     17	local_t		commit;
     18	char		data[4080];
     19};
     20
     21/* run time and sleep time in seconds */
     22#define RUN_TIME	10ULL
     23#define SLEEP_TIME	10
     24
     25/* number of events for writer to wake up the reader */
     26static int wakeup_interval = 100;
     27
     28static int reader_finish;
     29static DECLARE_COMPLETION(read_start);
     30static DECLARE_COMPLETION(read_done);
     31
     32static struct trace_buffer *buffer;
     33static struct task_struct *producer;
     34static struct task_struct *consumer;
     35static unsigned long read;
     36
     37static unsigned int disable_reader;
     38module_param(disable_reader, uint, 0644);
     39MODULE_PARM_DESC(disable_reader, "only run producer");
     40
     41static unsigned int write_iteration = 50;
     42module_param(write_iteration, uint, 0644);
     43MODULE_PARM_DESC(write_iteration, "# of writes between timestamp readings");
     44
     45static int producer_nice = MAX_NICE;
     46static int consumer_nice = MAX_NICE;
     47
     48static int producer_fifo;
     49static int consumer_fifo;
     50
     51module_param(producer_nice, int, 0644);
     52MODULE_PARM_DESC(producer_nice, "nice prio for producer");
     53
     54module_param(consumer_nice, int, 0644);
     55MODULE_PARM_DESC(consumer_nice, "nice prio for consumer");
     56
     57module_param(producer_fifo, int, 0644);
     58MODULE_PARM_DESC(producer_fifo, "use fifo for producer: 0 - disabled, 1 - low prio, 2 - fifo");
     59
     60module_param(consumer_fifo, int, 0644);
     61MODULE_PARM_DESC(consumer_fifo, "use fifo for consumer: 0 - disabled, 1 - low prio, 2 - fifo");
     62
     63static int read_events;
     64
     65static int test_error;
     66
     67#define TEST_ERROR()				\
     68	do {					\
     69		if (!test_error) {		\
     70			test_error = 1;		\
     71			WARN_ON(1);		\
     72		}				\
     73	} while (0)
     74
     75enum event_status {
     76	EVENT_FOUND,
     77	EVENT_DROPPED,
     78};
     79
     80static bool break_test(void)
     81{
     82	return test_error || kthread_should_stop();
     83}
     84
     85static enum event_status read_event(int cpu)
     86{
     87	struct ring_buffer_event *event;
     88	int *entry;
     89	u64 ts;
     90
     91	event = ring_buffer_consume(buffer, cpu, &ts, NULL);
     92	if (!event)
     93		return EVENT_DROPPED;
     94
     95	entry = ring_buffer_event_data(event);
     96	if (*entry != cpu) {
     97		TEST_ERROR();
     98		return EVENT_DROPPED;
     99	}
    100
    101	read++;
    102	return EVENT_FOUND;
    103}
    104
    105static enum event_status read_page(int cpu)
    106{
    107	struct ring_buffer_event *event;
    108	struct rb_page *rpage;
    109	unsigned long commit;
    110	void *bpage;
    111	int *entry;
    112	int ret;
    113	int inc;
    114	int i;
    115
    116	bpage = ring_buffer_alloc_read_page(buffer, cpu);
    117	if (IS_ERR(bpage))
    118		return EVENT_DROPPED;
    119
    120	ret = ring_buffer_read_page(buffer, &bpage, PAGE_SIZE, cpu, 1);
    121	if (ret >= 0) {
    122		rpage = bpage;
    123		/* The commit may have missed event flags set, clear them */
    124		commit = local_read(&rpage->commit) & 0xfffff;
    125		for (i = 0; i < commit && !test_error ; i += inc) {
    126
    127			if (i >= (PAGE_SIZE - offsetof(struct rb_page, data))) {
    128				TEST_ERROR();
    129				break;
    130			}
    131
    132			inc = -1;
    133			event = (void *)&rpage->data[i];
    134			switch (event->type_len) {
    135			case RINGBUF_TYPE_PADDING:
    136				/* failed writes may be discarded events */
    137				if (!event->time_delta)
    138					TEST_ERROR();
    139				inc = event->array[0] + 4;
    140				break;
    141			case RINGBUF_TYPE_TIME_EXTEND:
    142				inc = 8;
    143				break;
    144			case 0:
    145				entry = ring_buffer_event_data(event);
    146				if (*entry != cpu) {
    147					TEST_ERROR();
    148					break;
    149				}
    150				read++;
    151				if (!event->array[0]) {
    152					TEST_ERROR();
    153					break;
    154				}
    155				inc = event->array[0] + 4;
    156				break;
    157			default:
    158				entry = ring_buffer_event_data(event);
    159				if (*entry != cpu) {
    160					TEST_ERROR();
    161					break;
    162				}
    163				read++;
    164				inc = ((event->type_len + 1) * 4);
    165			}
    166			if (test_error)
    167				break;
    168
    169			if (inc <= 0) {
    170				TEST_ERROR();
    171				break;
    172			}
    173		}
    174	}
    175	ring_buffer_free_read_page(buffer, cpu, bpage);
    176
    177	if (ret < 0)
    178		return EVENT_DROPPED;
    179	return EVENT_FOUND;
    180}
    181
    182static void ring_buffer_consumer(void)
    183{
    184	/* toggle between reading pages and events */
    185	read_events ^= 1;
    186
    187	read = 0;
    188	/*
    189	 * Continue running until the producer specifically asks to stop
    190	 * and is ready for the completion.
    191	 */
    192	while (!READ_ONCE(reader_finish)) {
    193		int found = 1;
    194
    195		while (found && !test_error) {
    196			int cpu;
    197
    198			found = 0;
    199			for_each_online_cpu(cpu) {
    200				enum event_status stat;
    201
    202				if (read_events)
    203					stat = read_event(cpu);
    204				else
    205					stat = read_page(cpu);
    206
    207				if (test_error)
    208					break;
    209
    210				if (stat == EVENT_FOUND)
    211					found = 1;
    212
    213			}
    214		}
    215
    216		/* Wait till the producer wakes us up when there is more data
    217		 * available or when the producer wants us to finish reading.
    218		 */
    219		set_current_state(TASK_INTERRUPTIBLE);
    220		if (reader_finish)
    221			break;
    222
    223		schedule();
    224	}
    225	__set_current_state(TASK_RUNNING);
    226	reader_finish = 0;
    227	complete(&read_done);
    228}
    229
    230static void ring_buffer_producer(void)
    231{
    232	ktime_t start_time, end_time, timeout;
    233	unsigned long long time;
    234	unsigned long long entries;
    235	unsigned long long overruns;
    236	unsigned long missed = 0;
    237	unsigned long hit = 0;
    238	unsigned long avg;
    239	int cnt = 0;
    240
    241	/*
    242	 * Hammer the buffer for 10 secs (this may
    243	 * make the system stall)
    244	 */
    245	trace_printk("Starting ring buffer hammer\n");
    246	start_time = ktime_get();
    247	timeout = ktime_add_ns(start_time, RUN_TIME * NSEC_PER_SEC);
    248	do {
    249		struct ring_buffer_event *event;
    250		int *entry;
    251		int i;
    252
    253		for (i = 0; i < write_iteration; i++) {
    254			event = ring_buffer_lock_reserve(buffer, 10);
    255			if (!event) {
    256				missed++;
    257			} else {
    258				hit++;
    259				entry = ring_buffer_event_data(event);
    260				*entry = smp_processor_id();
    261				ring_buffer_unlock_commit(buffer, event);
    262			}
    263		}
    264		end_time = ktime_get();
    265
    266		cnt++;
    267		if (consumer && !(cnt % wakeup_interval))
    268			wake_up_process(consumer);
    269
    270#ifndef CONFIG_PREEMPTION
    271		/*
    272		 * If we are a non preempt kernel, the 10 seconds run will
    273		 * stop everything while it runs. Instead, we will call
    274		 * cond_resched and also add any time that was lost by a
    275		 * reschedule.
    276		 *
    277		 * Do a cond resched at the same frequency we would wake up
    278		 * the reader.
    279		 */
    280		if (cnt % wakeup_interval)
    281			cond_resched();
    282#endif
    283	} while (ktime_before(end_time, timeout) && !break_test());
    284	trace_printk("End ring buffer hammer\n");
    285
    286	if (consumer) {
    287		/* Init both completions here to avoid races */
    288		init_completion(&read_start);
    289		init_completion(&read_done);
    290		/* the completions must be visible before the finish var */
    291		smp_wmb();
    292		reader_finish = 1;
    293		wake_up_process(consumer);
    294		wait_for_completion(&read_done);
    295	}
    296
    297	time = ktime_us_delta(end_time, start_time);
    298
    299	entries = ring_buffer_entries(buffer);
    300	overruns = ring_buffer_overruns(buffer);
    301
    302	if (test_error)
    303		trace_printk("ERROR!\n");
    304
    305	if (!disable_reader) {
    306		if (consumer_fifo)
    307			trace_printk("Running Consumer at SCHED_FIFO %s\n",
    308				     consumer_fifo == 1 ? "low" : "high");
    309		else
    310			trace_printk("Running Consumer at nice: %d\n",
    311				     consumer_nice);
    312	}
    313	if (producer_fifo)
    314		trace_printk("Running Producer at SCHED_FIFO %s\n",
    315			     producer_fifo == 1 ? "low" : "high");
    316	else
    317		trace_printk("Running Producer at nice: %d\n",
    318			     producer_nice);
    319
    320	/* Let the user know that the test is running at low priority */
    321	if (!producer_fifo && !consumer_fifo &&
    322	    producer_nice == MAX_NICE && consumer_nice == MAX_NICE)
    323		trace_printk("WARNING!!! This test is running at lowest priority.\n");
    324
    325	trace_printk("Time:     %lld (usecs)\n", time);
    326	trace_printk("Overruns: %lld\n", overruns);
    327	if (disable_reader)
    328		trace_printk("Read:     (reader disabled)\n");
    329	else
    330		trace_printk("Read:     %ld  (by %s)\n", read,
    331			read_events ? "events" : "pages");
    332	trace_printk("Entries:  %lld\n", entries);
    333	trace_printk("Total:    %lld\n", entries + overruns + read);
    334	trace_printk("Missed:   %ld\n", missed);
    335	trace_printk("Hit:      %ld\n", hit);
    336
    337	/* Convert time from usecs to millisecs */
    338	do_div(time, USEC_PER_MSEC);
    339	if (time)
    340		hit /= (long)time;
    341	else
    342		trace_printk("TIME IS ZERO??\n");
    343
    344	trace_printk("Entries per millisec: %ld\n", hit);
    345
    346	if (hit) {
    347		/* Calculate the average time in nanosecs */
    348		avg = NSEC_PER_MSEC / hit;
    349		trace_printk("%ld ns per entry\n", avg);
    350	}
    351
    352	if (missed) {
    353		if (time)
    354			missed /= (long)time;
    355
    356		trace_printk("Total iterations per millisec: %ld\n",
    357			     hit + missed);
    358
    359		/* it is possible that hit + missed will overflow and be zero */
    360		if (!(hit + missed)) {
    361			trace_printk("hit + missed overflowed and totalled zero!\n");
    362			hit--; /* make it non zero */
    363		}
    364
    365		/* Calculate the average time in nanosecs */
    366		avg = NSEC_PER_MSEC / (hit + missed);
    367		trace_printk("%ld ns per entry\n", avg);
    368	}
    369}
    370
    371static void wait_to_die(void)
    372{
    373	set_current_state(TASK_INTERRUPTIBLE);
    374	while (!kthread_should_stop()) {
    375		schedule();
    376		set_current_state(TASK_INTERRUPTIBLE);
    377	}
    378	__set_current_state(TASK_RUNNING);
    379}
    380
    381static int ring_buffer_consumer_thread(void *arg)
    382{
    383	while (!break_test()) {
    384		complete(&read_start);
    385
    386		ring_buffer_consumer();
    387
    388		set_current_state(TASK_INTERRUPTIBLE);
    389		if (break_test())
    390			break;
    391		schedule();
    392	}
    393	__set_current_state(TASK_RUNNING);
    394
    395	if (!kthread_should_stop())
    396		wait_to_die();
    397
    398	return 0;
    399}
    400
    401static int ring_buffer_producer_thread(void *arg)
    402{
    403	while (!break_test()) {
    404		ring_buffer_reset(buffer);
    405
    406		if (consumer) {
    407			wake_up_process(consumer);
    408			wait_for_completion(&read_start);
    409		}
    410
    411		ring_buffer_producer();
    412		if (break_test())
    413			goto out_kill;
    414
    415		trace_printk("Sleeping for 10 secs\n");
    416		set_current_state(TASK_INTERRUPTIBLE);
    417		if (break_test())
    418			goto out_kill;
    419		schedule_timeout(HZ * SLEEP_TIME);
    420	}
    421
    422out_kill:
    423	__set_current_state(TASK_RUNNING);
    424	if (!kthread_should_stop())
    425		wait_to_die();
    426
    427	return 0;
    428}
    429
    430static int __init ring_buffer_benchmark_init(void)
    431{
    432	int ret;
    433
    434	/* make a one meg buffer in overwite mode */
    435	buffer = ring_buffer_alloc(1000000, RB_FL_OVERWRITE);
    436	if (!buffer)
    437		return -ENOMEM;
    438
    439	if (!disable_reader) {
    440		consumer = kthread_create(ring_buffer_consumer_thread,
    441					  NULL, "rb_consumer");
    442		ret = PTR_ERR(consumer);
    443		if (IS_ERR(consumer))
    444			goto out_fail;
    445	}
    446
    447	producer = kthread_run(ring_buffer_producer_thread,
    448			       NULL, "rb_producer");
    449	ret = PTR_ERR(producer);
    450
    451	if (IS_ERR(producer))
    452		goto out_kill;
    453
    454	/*
    455	 * Run them as low-prio background tasks by default:
    456	 */
    457	if (!disable_reader) {
    458		if (consumer_fifo >= 2)
    459			sched_set_fifo(consumer);
    460		else if (consumer_fifo == 1)
    461			sched_set_fifo_low(consumer);
    462		else
    463			set_user_nice(consumer, consumer_nice);
    464	}
    465
    466	if (producer_fifo >= 2)
    467		sched_set_fifo(producer);
    468	else if (producer_fifo == 1)
    469		sched_set_fifo_low(producer);
    470	else
    471		set_user_nice(producer, producer_nice);
    472
    473	return 0;
    474
    475 out_kill:
    476	if (consumer)
    477		kthread_stop(consumer);
    478
    479 out_fail:
    480	ring_buffer_free(buffer);
    481	return ret;
    482}
    483
    484static void __exit ring_buffer_benchmark_exit(void)
    485{
    486	kthread_stop(producer);
    487	if (consumer)
    488		kthread_stop(consumer);
    489	ring_buffer_free(buffer);
    490}
    491
    492module_init(ring_buffer_benchmark_init);
    493module_exit(ring_buffer_benchmark_exit);
    494
    495MODULE_AUTHOR("Steven Rostedt");
    496MODULE_DESCRIPTION("ring_buffer_benchmark");
    497MODULE_LICENSE("GPL");