Program Listing for File umapcpu.cpp

Return to documentation for file (umapcpu/umapcpu.cpp)

/*
 * This file is part of UMAP.  For copyright information see the COPYRIGHT file
 * in the top level directory, or at
 * https://github.com/LLNL/umap/blob/master/COPYRIGHT This program is free
 * software; you can redistribute it and/or modify it under the terms of the
 * GNU Lesser General Public License (as published by the Free Software
 * Foundation) version 2.1 dated February 1999.  This program is distributed in
 * the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
 * IMPLIED WARRANTY OF MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
 * the terms and conditions of the GNU Lesser General Public License for more
 * details.  You should have received a copy of the GNU Lesser General Public
 * License along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif // _GNU_SOURCE

#include <iostream>
#include <random>
#include <algorithm>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <stdint.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <pthread.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>    // optind
#include <errno.h>
#include <utmpx.h>
#include <parallel/algorithm>

#ifdef _OPENMP
#include <omp.h>
#endif

#include "umap/umap.h"
#include "../utility/commandline.hpp"
#include "../utility/umap_file.hpp"

#define handle_error_en(en, msg) \
  do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)

void cpu_setcpu(int cpu)
{
  int s;
  cpu_set_t cpuset;
  pthread_t thread;

  thread = pthread_self();

  CPU_ZERO(&cpuset);
  CPU_SET(cpu, &cpuset);

  s = pthread_setaffinity_np(thread, sizeof(cpu_set_t), &cpuset);
  if (s != 0)
    handle_error_en(s, "pthread_setaffinity_np");

  /* Check the actual affinity mask assigned to the thread */

  s = pthread_getaffinity_np(thread, sizeof(cpu_set_t), &cpuset);
  if (s != 0)
    handle_error_en(s, "pthread_getaffinity_np");
}
static inline uint64_t getns(void)
{
  struct timespec ts;
  int ret = clock_gettime(CLOCK_MONOTONIC, &ts);
  assert(ret == 0);
  return (((uint64_t)ts.tv_sec) * 1000000000ULL) + ts.tv_nsec;
}

void initdata(uint64_t *region, int64_t rlen) {
  fprintf(stdout, "initdata: %p, %ld\n", region, rlen);
#pragma omp parallel for
  for(int64_t i=0; i< rlen; ++i) {
    region[i] = (uint64_t) (rlen - i);
  }
}

int main(int argc, char **argv)
{
  utility::umt_optstruct_t options;
  long pagesize;
  int64_t totalbytes;
  uint64_t arraysize;
  void* base_addr;
  std::random_device rd;
  std::mt19937 gen(rd());
  std::uniform_int_distribution<int> rnd_int(0, 39);

  pagesize = utility::umt_getpagesize();

  umt_getoptions(&options, argc, argv);

  omp_set_num_threads(options.numthreads);

  totalbytes = options.numpages*pagesize;
  base_addr = utility::map_in_file(options.filename, options.initonly,
      options.noinit, options.usemmap, totalbytes);
  assert(base_addr != NULL);

  fprintf(stdout, "%lu pages, %lu threads\n", options.numpages, options.numthreads);

  uint64_t *arr = (uint64_t *) base_addr;
  arraysize = totalbytes/sizeof(int64_t);

  uint64_t start = getns();
  if ( !options.noinit ) {
    // init data
    initdata(arr, arraysize);
    fprintf(stdout, "Init took %f us\n", (double)(getns() - start)/1000000.0);
  }

  const int testpages = 400;

  if ( !options.initonly )
  {
    std::vector<int> cpus{0, 10, 20, 30};

    start = getns();
#pragma omp parallel for
    for (uint64_t page = 0; page < options.numpages - testpages; page += testpages) {
      uint64_t sum = 0;

      //cpu_setcpu(10);
      for (int x = 0; x < testpages; x++) {
        uint64_t* p = &arr[(page+x)*(pagesize/sizeof(uint64_t*))];
        sum += *p;
      }

      cpu_setcpu(rnd_int(gen));

      //cpu_setcpu(30);
      for (int x = 0; x < testpages; ++x) {
        uint64_t* p = &arr[(page+x)*(pagesize/sizeof(uint64_t*))];
        *p = sum;
      }
    }

    fprintf(stdout, "test took %f us\n", (double)(getns() - start)/1000000.0);
  }

  utility::unmap_file(options.usemmap, totalbytes, base_addr);

  return 0;
}