Ankkaserver


    __
  >(' )
    )/
    /(
   /  `----/
   \  ~=- /
 ~^~^~^~^~^~^~^

Navigointi
Etusivu
PhpSysInfo
~sami/
Blogi
vnstat
Ladattavaa
Virityksiä
Muuta
Linkkejä
Monsujen tappopeli
Vieraskirja
Chat

Kuormitusohjelma

Tämä ohjelma laskee alkulukuja. Tämän ohjelman tarkoitus ei ole kuitenkaan laskea alkulukuja mahdollisimman nopeasti, vaan antaa tietokoneelle mahdollisimman paljon oikeaa raskaahkoa hyötykäyttöä vastaava kuorma. Ohjelma kirjoittaa ja lukee lukuarvoja muistista inkrementoiden muistiosoitinta viimeisimpänä löydetyllä alkuluvulla, jolloin prosessorin branch predictorin on lähes mahdotonta arvata silmukan tämänkertaista kulkua. Muistin runsas käyttö myös estää suuren määrän rekistereitä omaavia RISC-prosessoreita saamasta testissä merkittävää suorituskykyetua.

Jokainen alkuluku lasketaan ja tarkistetaan 16 (REPEAT_COUNT) kertaa. Jokaiselle alkulukuja laskevalle säikeelle varataan 32 megatavua (MEMORY_USE) muistia, ja varattuun muistialueeseen kohdistetaan luku- ja kirjoitusoperaatioita.

Koodi kääntyy GCC:llä ja useimmilla POSIX-yhteensopivilla kääntäjillä useimmilla POSIX-yhteensopivilla käyttöjärjestelmillä toimivaksi ohjelmaksi.

Tätä ohjelmaa voi käyttää eri tietokoneiden välisten nopeuserojen vertailuun. Ohjelma ei toimi oikein, jos säikeiden määrä ei ole kahden potenssi.

// Käännä: gcc primes.c -lpthread
// käytä: ./a.out [coret] [laskettavien alkulukujen määrä]
 
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <pthread.h>
#include <time.h>
#include <sys/time.h>
#include <unistd.h>

struct worker_args
{
  unsigned worker_id;
  unsigned primes;
};
 
static inline int64_t isqrt(int64_t x)
{
  int64_t q = 1;
  int64_t r = 0;
  int64_t t;

  while (<= x)
    q <<= 2;

  while (> 1)
  {
    int64_t t;
    q >>= 2;
    t = x - r - q;
    r >>= 1;
    if (>= 0)
    {
      x = t;
      r += q;
    }
  }
  return r;
}

static inline int is_prime(unsigned p)
{
  unsigned d;
  unsigned r;
 
  r = isqrt(p);
  d = 3;
  do
    if(!(% d))
      return 0;
  while((+= 2) <= r);
  return 1;
}
 
unsigned thread_count;
unsigned increment;
unsigned primes = -1;
unsigned total_primes;
volatile unsigned largest_prime;
volatile unsigned ready_count = 0;
pthread_t *threads; 
static pthread_mutex_t lock;

#define REPEAT_COUNT 16
#define MEMORY_USE 1024*1024*32

void *info_thread(void *ptr)
{
  while(1)
  {
    sleep(1);
    printf("%u primes calculated.\n", ready_count);
  }
}
 
void *worker_thread(struct worker_args *ptr)
{
  unsigned last_prime = 3;
  unsigned p = last_prime + (ptr->worker_id << 1);
  unsigned i = ptr->primes;
  unsigned repeats;
  unsigned was_prime, was_prime_check;
  volatile unsigned *mem_block = malloc(MEMORY_USE*sizeof(unsigned));
  volatile register unsigned integer;
  unsigned mem_index = 0;
  unsigned inc_count = increment;
  unsigned n;
 
  if(!mem_block) puts("Out of memory");

  printf("Thread %u starting counting from %u. Incrementing by %u.\n", ptr->worker_id, p, increment);
 
  loop:do
  {
    for(repeats=0;repeats<REPEAT_COUNT;repeats++)
    {
      if((was_prime = is_prime(p)))
      {
        // if was prime, write to memory
        mem_index += p;
        mem_block[mem_index & (MEMORY_USE-1)] = p;
      }
      else
      {
        // else read from memory
        integer = mem_block[(mem_index+=last_prime) & (MEMORY_USE-1)];
        if(integer != mem_block[mem_index & (MEMORY_USE-1)])
          printf("Memory error detected in thread %u! (Prime: %u, retry count: %u)\n", ptr->worker_id, repeats);;
      }
      if(!repeats) was_prime_check = was_prime;
      else if(was_prime != was_prime_check)
        printf("CPU error detected in thread %u! (Prime: %u, retry count: %u)\n", ptr->worker_id, repeats);
    }
    if(was_prime)
    {
      last_prime = p;
      i--;
      pthread_mutex_lock(&lock);
      ready_count++;
      if(last_prime > largest_prime)
        largest_prime = last_prime;
      pthread_mutex_unlock(&lock);
    }
    p += inc_count;
  }
  while(i);

  // if (total_primes / thread_count) is not an integer,
  // calculate the rest using worker 0
  if(!ptr->worker_id && inc_count != 2 && total_primes != thread_count * ptr->primes)
  {
    inc_count = 2;
    i = total_primes - (thread_count * ptr->primes);
    // wait until all other threads have exited
    for(n=thread_count;--n;)
      pthread_join(threads[n], 0);
    p = last_prime = largest_prime + inc_count;
    printf("%u primes calculated.\n", ready_count);
    printf("Calculating last primes using worker 0. Starting from number %u (last prime %u), %u primes left.\n", p, p - inc_count, i);
    goto loop;
  }

  printf("Thread %u exiting.\n", ptr->worker_id);
  pthread_exit(0);
}
 
int main(int argc, char **argv)
{
  unsigned n, t;
  unsigned long retvals;
  struct timeval tv0, tv1;
  unsigned long long ms;
  pthread_t infothread;
  struct worker_args *worker_args;
 
  if(argc < 2)
    return 1;
 
  thread_count = n = atoi(argv[1]);
 
  if(argc == 3)
    primes = (total_primes = atoi(argv[2])) / thread_count;

  pthread_mutex_init(&lock, 0);
 
  increment = n << 1;
  printf("Starting %u threads.\n", n);
  threads = malloc(* sizeof(pthread_t));
  worker_args = malloc(* sizeof(struct worker_args));
  gettimeofday(&tv0, 0);
  while(n--)
  {
    worker_args[n].worker_id = n;
    worker_args[n].primes = primes;
    if(pthread_create(&threads[n], NULL, (void*)worker_thread, &worker_args[n]))
      puts("Error while creating new thread");
  }

  if(pthread_create(&infothread, NULL, info_thread, 0))
    puts("Error while creating new thread");
 
  while(++< thread_count)
    pthread_join(threads[n], 0);

  gettimeofday(&tv1, 0);

  ms = tv1.tv_sec * 1000000 + tv1.tv_usec;
  ms -= tv0.tv_sec * 1000000 + tv0.tv_usec;

  printf("%u threads: %u primes calculated in %llu.%.6llu seconds. %u error checks. %u megabytes memory per thread.\n", thread_count, ready_count,
         ms/1000000, ms%1000000, REPEAT_COUNT, MEMORY_USE/1024/1024);
 
  return 0;
}


 05:18:07 up 38 days,  8:00,  2 users,  load average: 0.44, 0.29, 0.23
               total        used        free      shared  buff/cache   available
Mem:             493         120         118           3         254         356
Swap:            486         126         360

Valid HTML 4.01 Strict Valid CSS!

http://sininenankka.dy.fi
Tietoja ylläpitäjästä

Sivun generointi kesti 4.815 s