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 (q <= x) q <<= 2;
while (q > 1) { int64_t t; q >>= 2; t = x - r - q; r >>= 1; if (t >= 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(!(p % d)) return 0; while((d += 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(n * sizeof(pthread_t)); worker_args = malloc(n * 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(++n < 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; }
|