/* The sender routine is very similar to the receiver. */ static void link_sender(int index, int linkno, int channel) { char *buf = NULL; int *wbuf; int checksum; int i; int size; int iterations; buf = malloc(MaxLinkTransfer); if (buf == NULL) Fatal("sender for link %d : out of memory.", linkno); wbuf = (int *) buf; /* Perform an initial write to set up the pipe. */ if (write(channel, buf, sizeof(int)) != sizeof(int)) Fatal("sender for link %d : failed to send initial data.", linkno); Signal(&ThreadsReady); /* checked by memory tester */ for (iterations = 0; ; iterations++) { bool temp = Finished; if (write(channel, (char *) &temp, sizeof(bool)) != sizeof(bool)) Fatal("sender for link %d : write error %d sending Finished flag.", linkno, errno); if (temp) break; for (size = 8; size <= MaxLinkTransfer; size *= 2) { for (i = 1, checksum = 0; i < (size / sizeof(int)); i++) { wbuf[i] = hw_rand(); checksum += wbuf[i]; } wbuf[0] = checksum; if (write(channel, buf, size) != size) Fatal("sender for link %d : write error %d sending block of %d bytes.", linkno, errno, size); } } /* The Finished flag has been set and the remote receiving end */ /* has been informed. It is time to update the results */ /* structure. */ Wait(&ResultsLock); Results.LinkStats[index].LinkNumber = linkno; Results.LinkStats[index].WriteIterations = iterations; Signal(&ResultsLock); Signal(&ResultsReady); /* Sender all done. */ }
static void check_fast(void) { Carrier *carrier = NULL; int checksum; int i; int tmp; int *wptr; int failures = 0; int iterations = 0; carrier = AllocFast(FastmemSize, &(MyTask->MemPool)); Signal(&ThreadsReady); if (carrier == NULL) { Report("warning, failed to allocate on-chip memory."); Wait(&ResultsLock); Results.OnchipMemory = 0; Results.OnchipFailures = 0; Signal(&ResultsLock); Signal(&ResultsReady); return; } /* Fill the on-chip memory with random data. */ wptr = (int *) carrier->Addr; for (i = 0, checksum = 0; i < (FastmemSize / sizeof(int)); i++) { wptr[i] = hw_rand(); checksum += wptr[i]; } for (iterations = 0; ; iterations++) { for (i = 0; (i < MemoryInterval) && !Finished; i++) Delay(OneSec); if (Finished) break; for (i = 0, tmp = 0; i < (FastmemSize / sizeof(int)); i++) tmp += wptr[i]; if (tmp != checksum) { failures++; checksum = tmp; } } Wait(&ResultsLock); Results.OnchipMemory = FastmemSize; Results.OnchipFailures = failures; Results.OnchipIterations = iterations; Signal(&ResultsLock); Signal(&ResultsReady); }
uint32_t custom_rand_generate(void) { return hw_rand(); }
/*}}}*/ static void controller_routine(char *arg) { int number_workers; int first_channel; int i; char *buf; int *wbuf; int endtime; int size; int checksum; int worker; FullStats stats; #define to_worker(i) (first_channel + i + i + 1) #define from_worker(i) (first_channel + i + i) /*{{{ initialise */ if (sscanf(arg, "%d.%d", &number_workers, &first_channel) != 2) Fatal("controller routine, invalid argument %s", arg); logname = getenv("HWTEST_LOGFILE"); if (logname == NULL) logname = "/helios/local/tests/hwtest/hwtest.log"; buf = malloc(MaxCommsTransfer); if (buf == NULL) Fatal("controller routine, out of memory."); wbuf = (int *) buf; for (worker = 0; worker < number_workers; worker++) { if (write(to_worker(worker), buf, sizeof(int)) != sizeof(int)) Fatal("controller routine, failed to send initial data to worker %d", worker); if (full_read(from_worker(worker), buf, sizeof(int)) != sizeof(int)) Fatal("controller routine, failed to receive initial data from worker %d", worker); } /* The main memory tester can now allocate its buffers. */ Signal(&ThreadsReady); endtime = ((((24 * Days) + Hours) * 60) + Minutes) * 60; endtime += time(NULL); /*}}}*/ /*{{{ communication with workers */ while (endtime > time(NULL)) { if (!ExtraComms) { Delay(5 * OneSec); continue; } for (size = 32; size <= MaxCommsTransfer; size *= 2) { /* initialise the buffer with random data. */ wbuf[0] = 0; /* checksum */ for (i = 1; i < (size / sizeof(int)); i++) { wbuf[i] = hw_rand(); wbuf[0] += wbuf[i]; } for (worker = 0; worker < number_workers; worker++) { if (write(to_worker(worker), (char *) &size, sizeof(int)) != sizeof(int)) Fatal("controller routine failed to send size %d to worker %d", size, worker); if (write(to_worker(worker), buf, size) != size) Fatal("controller routine failed to write block of %d bytes to worker %d", size, worker); if (full_read(from_worker(worker), buf, size) != size) Fatal("controller routine, failed to read back buffer of %d bytes from worker %d", size, worker); for (i = 1, checksum = 0; i < (size / sizeof(int)); i++) checksum += wbuf[i]; if (checksum != wbuf[0]) { Report("controller routine, corruption in buffer of %d bytes read back from worker %d", size, worker); wbuf[0] = checksum; } } /* for all the workers */ if (endtime < time(NULL)) break; } /* sizes loop */ } /* while (endtime > time()) */ /*}}}*/ /*{{{ terminating the workers */ /* At this point the runtime has expired and it is necessary */ /* to send a terminate message to all the workers. Also the */ /* Finished flag should be set so that the testing going on */ /* within the controller will stop. */ Finished = TRUE; size = 0; for (worker = 0; worker < number_workers; worker++) if (write(to_worker(worker), (char *) &size, sizeof(int)) != sizeof(int)) Fatal("controller routine, failed to send terminate request to worker %d", worker); /*}}}*/ /*{{{ collecting the stats */ /* Now collect together the results from all the workers. */ TotalStats.OffchipMemoryG = TotalStats.OffchipMemoryM = TotalStats.OffchipMemoryK = TotalStats.OffchipFailures = TotalStats.OnchipMemoryG = TotalStats.OnchipMemoryM = TotalStats.OnchipMemoryK = TotalStats.OnchipFailures = TotalStats.LinkG = TotalStats.LinkM = TotalStats.LinkK = TotalStats.LinkFailures = 0; for (worker = 0; worker < number_workers; worker++) { if (full_read(from_worker(worker), (char *) &stats, sizeof(FullStats)) != sizeof(FullStats)) Fatal("controller routine, failed to collect results from worker %d", worker); if (Verbose) display_results(&stats); TotalStats.OffchipMemoryK += stats.OffchipMemory; TotalStats.OffchipFailures += stats.OffchipFailures; TotalStats.OnchipMemoryK += stats.OnchipMemory; TotalStats.OnchipFailures += stats.OnchipFailures; for (i = 0; i < stats.NumberLinks; i++) { TotalStats.LinkK += stats.LinkStats[i].ReadIterations; TotalStats.LinkFailures += stats.LinkStats[i].ReadFailures; } } /* Include the results from the test routines running */ /* within this worker. */ for (i = 1; i < NumberThreads; i++) Wait(&ResultsReady); TotalStats.OffchipMemoryK += Results.OffchipMemory; TotalStats.OffchipFailures += Results.OffchipFailures; TotalStats.OnchipMemoryK += Results.OnchipMemory; TotalStats.OnchipFailures += Results.OnchipFailures; for (i = 0; i < Results.NumberLinks; i++) { TotalStats.LinkK += stats.LinkStats[i].ReadIterations; TotalStats.LinkFailures += stats.LinkStats[i].ReadFailures; } /*}}}*/ /*{{{ calculate the real stats */ /* The stats structure now contains the total amount of memory */ /* that has been checked, plus the total number of link */ /* iterations. This has to be converted to KByte hours etc, */ /* taking some care to avoid overflow. Running on very large */ /* networks with 256 4Mbyte processors for a whole week should */ /* still be OK - just. */ /* 1) divide by 60 to give a minutes rating. */ TotalStats.OffchipMemoryK /= 60; TotalStats.OnchipMemoryK /= 60; /* 2) now multiply by the number of minutes in the run */ TotalStats.OffchipMemoryK *= ((((Days * 24) + Hours) * 60) + Minutes); TotalStats.OnchipMemoryK *= ((((Days * 24) + Hours) * 60) + Minutes); /* 3) on-chip sizes were in bytes, not K */ TotalStats.OnchipMemoryK /= 1024; /* 4) update G and M values */ TotalStats.OffchipMemoryM = TotalStats.OffchipMemoryK / 1024; TotalStats.OffchipMemoryK = TotalStats.OffchipMemoryK % 1024; TotalStats.OffchipMemoryG = TotalStats.OffchipMemoryM / 1024; TotalStats.OffchipMemoryM = TotalStats.OffchipMemoryM % 1024; TotalStats.OnchipMemoryM = TotalStats.OnchipMemoryK / 1024; TotalStats.OnchipMemoryK = TotalStats.OnchipMemoryK % 1024; TotalStats.OnchipMemoryG = TotalStats.OnchipMemoryM / 1024; TotalStats.OnchipMemoryM = TotalStats.OnchipMemoryM % 1024; /* 5) update link stats in much the same way */ TotalStats.LinkK /= 32; TotalStats.LinkK *= DataPerIteration; TotalStats.LinkK /= 32; /* 32 * 32 == 1K */ TotalStats.LinkM = TotalStats.LinkK / 1024; TotalStats.LinkK = TotalStats.LinkK % 1024; TotalStats.LinkG = TotalStats.LinkM / 1024; TotalStats.LinkM = TotalStats.LinkM % 1024; if (Verbose) { printf("Summary for this run.\n\n"); printf(str4, TotalStats.OffchipMemoryG, TotalStats.OffchipMemoryM, TotalStats.OffchipMemoryK, TotalStats.OffchipFailures); printf(str5, TotalStats.OnchipMemoryG, TotalStats.OnchipMemoryM, TotalStats.OnchipMemoryK, TotalStats.OnchipFailures); printf(str6, TotalStats.LinkG, TotalStats.LinkM, TotalStats.LinkK, TotalStats.LinkFailures); puts("\n"); } /*}}}*/ /*{{{ update the log file info */ readin_logfile(); /* automatically created if necessary */ LogStats.OffchipMemoryG += TotalStats.OffchipMemoryG; LogStats.OffchipMemoryM += TotalStats.OffchipMemoryM; LogStats.OffchipMemoryK += TotalStats.OffchipMemoryK; LogStats.OnchipMemoryG += TotalStats.OnchipMemoryG; LogStats.OnchipMemoryM += TotalStats.OnchipMemoryM; LogStats.OnchipMemoryK += TotalStats.OnchipMemoryK; LogStats.OffchipFailures += TotalStats.OffchipFailures; LogStats.OnchipFailures += TotalStats.OnchipFailures; LogStats.LinkG += TotalStats.LinkG; LogStats.LinkM += TotalStats.LinkM; LogStats.LinkK += TotalStats.LinkK; LogStats.LinkFailures += TotalStats.LinkFailures; /* And adjust these results as appropriate */ LogStats.OffchipMemoryM += LogStats.OffchipMemoryK / 1024; LogStats.OffchipMemoryK %= 1024; LogStats.OffchipMemoryG += LogStats.OffchipMemoryM / 1024; LogStats.OffchipMemoryM %= 1024; LogStats.OnchipMemoryM += LogStats.OnchipMemoryK / 1024; LogStats.OnchipMemoryK %= 1024; LogStats.OnchipMemoryG += LogStats.OnchipMemoryM / 1024; LogStats.OnchipMemoryM %= 1024; LogStats.LinkM += LogStats.LinkK / 1024; LogStats.LinkK %= 1024; LogStats.LinkG += LogStats.LinkM / 1024; LogStats.LinkM %= 1024; NumberHours += ((24 * Days) + Hours); writeout_logfile(); /*}}}*/ }
/*{{{ main memory checking */ static void check_mem(void) { int size; int i; char *buf; int *wbuf; int checksum; int tmp; int failures = 0; int iterations = 0; /* Before allocating memory it is necessary to wait for the */ /* various other threads to allocate their buffers. */ for (i = 1; i < NumberThreads; i++) Wait(&ThreadsReady); /* Now examine the free pool to determine the amount of memory */ /* to get. The system is left with 50K of memory for buffering */ /* etc. */ size = GetRoot()->FreePool->Size; size -= (50 * 1024); size = (size + 1023) & ~1023; /* If the TFM is running on this processor reduce the memory */ /* size. The TFM may need more memory as well as the kernel and */ /* Processor Manager. */ { Object *tmp = Locate(NULL, "/loader/tfm"); if (tmp != NULL) { size -= (50 * 1024); Close(tmp); } tmp = Locate(NULL, "/loader/netserv"); if (tmp != NULL) { size -= (50 * 1024); Close(tmp); } } /* Now try to get hold of a suitable buffer. The memory may */ /* be fragmented so it is necessary to try smaller and smaller */ /* mallocs. */ for (buf = NULL; (buf == NULL) && (size > 0); size -= (10 * 1024)) buf = malloc(size); if (buf == NULL) { Report("main memory checker, failed to allocate a buffer"); Wait(&ResultsLock); Results.OffchipMemory = 0; Results.OffchipFailures = 0; Signal(&ResultsLock); Signal(&ResultsReady); return; } /* Fill the buffer with random data and calculate the checksum */ wbuf = (int *) buf; for (i = 0, checksum = 0; i < (size / sizeof(int)); i++) { wbuf[i] = hw_rand(); checksum += wbuf[i]; } for (iterations = 0; ; iterations++) { for (i = 0; (i < MemoryInterval) && !Finished; i++) Delay(OneSec); if (Finished) break; for (i = 0, tmp = 0; i < (size / sizeof(int)); i++) tmp += wbuf[i]; if (tmp != checksum) { checksum = tmp; failures++; } } Wait(&ResultsLock); Results.OffchipMemory = size / 1024; Results.OffchipFailures = failures; Results.OffchipIterations = iterations; Signal(&ResultsLock); Signal(&ResultsReady); }