linux/tools/testing/selftests/resctrl/fill_buf.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * fill_buf benchmark
   4 *
   5 * Copyright (C) 2018 Intel Corporation
   6 *
   7 * Authors:
   8 *    Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>,
   9 *    Fenghua Yu <fenghua.yu@intel.com>
  10 */
  11#include <stdio.h>
  12#include <unistd.h>
  13#include <stdlib.h>
  14#include <sys/types.h>
  15#include <sys/wait.h>
  16#include <inttypes.h>
  17#include <malloc.h>
  18#include <string.h>
  19
  20#include "resctrl.h"
  21
  22#define CL_SIZE                 (64)
  23#define PAGE_SIZE               (4 * 1024)
  24#define MB                      (1024 * 1024)
  25
  26static unsigned char *startptr;
  27
  28static void sb(void)
  29{
  30#if defined(__i386) || defined(__x86_64)
  31        asm volatile("sfence\n\t"
  32                     : : : "memory");
  33#endif
  34}
  35
  36static void ctrl_handler(int signo)
  37{
  38        free(startptr);
  39        printf("\nEnding\n");
  40        sb();
  41        exit(EXIT_SUCCESS);
  42}
  43
  44static void cl_flush(void *p)
  45{
  46#if defined(__i386) || defined(__x86_64)
  47        asm volatile("clflush (%0)\n\t"
  48                     : : "r"(p) : "memory");
  49#endif
  50}
  51
  52static void mem_flush(void *p, size_t s)
  53{
  54        char *cp = (char *)p;
  55        size_t i = 0;
  56
  57        s = s / CL_SIZE; /* mem size in cache llines */
  58
  59        for (i = 0; i < s; i++)
  60                cl_flush(&cp[i * CL_SIZE]);
  61
  62        sb();
  63}
  64
  65static void *malloc_and_init_memory(size_t s)
  66{
  67        uint64_t *p64;
  68        size_t s64;
  69
  70        void *p = memalign(PAGE_SIZE, s);
  71
  72        p64 = (uint64_t *)p;
  73        s64 = s / sizeof(uint64_t);
  74
  75        while (s64 > 0) {
  76                *p64 = (uint64_t)rand();
  77                p64 += (CL_SIZE / sizeof(uint64_t));
  78                s64 -= (CL_SIZE / sizeof(uint64_t));
  79        }
  80
  81        return p;
  82}
  83
  84static int fill_one_span_read(unsigned char *start_ptr, unsigned char *end_ptr)
  85{
  86        unsigned char sum, *p;
  87
  88        sum = 0;
  89        p = start_ptr;
  90        while (p < end_ptr) {
  91                sum += *p;
  92                p += (CL_SIZE / 2);
  93        }
  94
  95        return sum;
  96}
  97
  98static
  99void fill_one_span_write(unsigned char *start_ptr, unsigned char *end_ptr)
 100{
 101        unsigned char *p;
 102
 103        p = start_ptr;
 104        while (p < end_ptr) {
 105                *p = '1';
 106                p += (CL_SIZE / 2);
 107        }
 108}
 109
 110static int fill_cache_read(unsigned char *start_ptr, unsigned char *end_ptr,
 111                           char *resctrl_val)
 112{
 113        int ret = 0;
 114        FILE *fp;
 115
 116        while (1) {
 117                ret = fill_one_span_read(start_ptr, end_ptr);
 118                if (!strncmp(resctrl_val, CAT_STR, sizeof(CAT_STR)))
 119                        break;
 120        }
 121
 122        /* Consume read result so that reading memory is not optimized out. */
 123        fp = fopen("/dev/null", "w");
 124        if (!fp)
 125                perror("Unable to write to /dev/null");
 126        fprintf(fp, "Sum: %d ", ret);
 127        fclose(fp);
 128
 129        return 0;
 130}
 131
 132static int fill_cache_write(unsigned char *start_ptr, unsigned char *end_ptr,
 133                            char *resctrl_val)
 134{
 135        while (1) {
 136                fill_one_span_write(start_ptr, end_ptr);
 137                if (!strncmp(resctrl_val, CAT_STR, sizeof(CAT_STR)))
 138                        break;
 139        }
 140
 141        return 0;
 142}
 143
 144static int
 145fill_cache(unsigned long long buf_size, int malloc_and_init, int memflush,
 146           int op, char *resctrl_val)
 147{
 148        unsigned char *start_ptr, *end_ptr;
 149        unsigned long long i;
 150        int ret;
 151
 152        if (malloc_and_init)
 153                start_ptr = malloc_and_init_memory(buf_size);
 154        else
 155                start_ptr = malloc(buf_size);
 156
 157        if (!start_ptr)
 158                return -1;
 159
 160        startptr = start_ptr;
 161        end_ptr = start_ptr + buf_size;
 162
 163        /*
 164         * It's better to touch the memory once to avoid any compiler
 165         * optimizations
 166         */
 167        if (!malloc_and_init) {
 168                for (i = 0; i < buf_size; i++)
 169                        *start_ptr++ = (unsigned char)rand();
 170        }
 171
 172        start_ptr = startptr;
 173
 174        /* Flush the memory before using to avoid "cache hot pages" effect */
 175        if (memflush)
 176                mem_flush(start_ptr, buf_size);
 177
 178        if (op == 0)
 179                ret = fill_cache_read(start_ptr, end_ptr, resctrl_val);
 180        else
 181                ret = fill_cache_write(start_ptr, end_ptr, resctrl_val);
 182
 183        if (ret) {
 184                printf("\n Error in fill cache read/write...\n");
 185                return -1;
 186        }
 187
 188        free(startptr);
 189
 190        return 0;
 191}
 192
 193int run_fill_buf(unsigned long span, int malloc_and_init_memory,
 194                 int memflush, int op, char *resctrl_val)
 195{
 196        unsigned long long cache_size = span;
 197        int ret;
 198
 199        /* set up ctrl-c handler */
 200        if (signal(SIGINT, ctrl_handler) == SIG_ERR)
 201                printf("Failed to catch SIGINT!\n");
 202        if (signal(SIGHUP, ctrl_handler) == SIG_ERR)
 203                printf("Failed to catch SIGHUP!\n");
 204
 205        ret = fill_cache(cache_size, malloc_and_init_memory, memflush, op,
 206                         resctrl_val);
 207        if (ret) {
 208                printf("\n Error in fill cache\n");
 209                return -1;
 210        }
 211
 212        return 0;
 213}
 214