Merge pull request #2564 from reactormonk/jpoirier-realtimeGCTest

Jpoirier realtime gc test
This commit is contained in:
Andreas Rumpf
2015-05-14 02:06:11 +02:00
9 changed files with 260 additions and 2 deletions

View File

@@ -3,8 +3,11 @@ Each test must have a filename of the form: ``t*.nim``
Each test can contain a spec in a ``discard """"""`` block.
The folder ``rodfiles`` contains special tests that test incremental
The folder ``rodfiles`` contains special tests that test incremental
compilation via symbol files.
The folder ``dll`` contains simple DLL tests.
The folder ``realtimeGC`` contains a test for validating that the realtime GC
can run properly without linking against the nimrtl.dll/so. It includes a C
client and platform specific build files for manual compilation.

67
tests/realtimeGC/cmain.c Normal file
View File

@@ -0,0 +1,67 @@
#ifdef WIN
#include <windows.h>
#else
#include <dlfcn.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <time.h>
#define RUNTIME (15*60)
typedef void (*pFunc)(void);
int main(int argc, char* argv[])
{
int i;
void* hndl;
pFunc status;
pFunc count;
pFunc checkOccupiedMem;
#ifdef WIN
hndl = (void*) LoadLibrary((char const*)"./tests/realtimeGC/shared.dll");
status = (pFunc)GetProcAddress((HMODULE) hndl, (char const*)"status");
count = (pFunc)GetProcAddress((HMODULE) hndl, (char const*)"count");
checkOccupiedMem = (pFunc)GetProcAddress((HMODULE) hndl, (char const*)"checkOccupiedMem");
#else /* OSX || NIX */
hndl = (void*) dlopen((char const*)"./tests/realtimeGC/libshared.so", RTLD_LAZY);
status = (pFunc) dlsym(hndl, (char const*)"status");
count = (pFunc) dlsym(hndl, (char const*)"count");
checkOccupiedMem = (pFunc) dlsym(hndl, (char const*)"checkOccupiedMem");
#endif
assert(hndl);
assert(status);
assert(count);
assert(checkOccupiedMem);
time_t startTime = time((time_t*)0);
time_t runTime = (time_t)(RUNTIME);
time_t accumTime = 0;
while (accumTime < runTime) {
for (i = 0; i < 10; i++)
count();
/* printf("1. sleeping...\n"); */
sleep(1);
for (i = 0; i < 10; i++)
status();
/* printf("2. sleeping...\n"); */
sleep(1);
checkOccupiedMem();
accumTime = time((time_t*)0) - startTime;
/* printf("--- Minutes left to run: %d\n", (int)(runTime-accumTime)/60); */
}
printf("Cleaning up the shared object pointer...\n");
#ifdef WIN
FreeLibrary((HMODULE)hndl);
#else /* OSX || NIX */
dlclose(hndl);
#endif
printf("Done\n");
return 0;
}

View File

@@ -0,0 +1,6 @@
--app:console
--threads:on
-d:release
-d:useRealtimeGC

View File

@@ -0,0 +1,46 @@
discard """
cmd: "nim $target --debuginfo $options $file"
output: "Done"
"""
import times, os, threadpool
const RUNTIME = 15 * 60 # 15 minutes
when defined(windows):
const dllname = "./tests/realtimeGC/shared.dll"
elif defined(macosx):
const dllname = "./tests/realtimeGC/libshared.dylib"
else:
const dllname = "./tests/realtimeGC/libshared.so"
proc status() {.importc: "status", dynlib: dllname.}
proc count() {.importc: "count", dynlib: dllname.}
proc checkOccupiedMem() {.importc: "checkOccupiedMem", dynlib: dllname.}
proc process() =
let startTime = getTime()
let runTime = cast[Time](RUNTIME) #
var accumTime: Time
while accumTime < runTime:
for i in 0..10:
count()
# echo("1. sleeping... ")
sleep(500)
for i in 0..10:
status()
# echo("2. sleeping... ")
sleep(500)
checkOccupiedMem()
accumTime = cast[Time]((getTime() - startTime))
# echo("--- Minutes left to run: ", int(int(runTime-accumTime)/60))
proc main() =
process()
# parallel:
# for i in 0..0:
# spawn process()
# sync()
echo("Done")
main()

View File

@@ -0,0 +1,21 @@
Test the realtime GC without linking nimrtl.dll/so.
Note, this is a long running test, default is 35 minutes. To change the
the run time see RUNTIME in main.nim and main.c.
You can build shared.nim, main.nim, and main.c by running make (nix systems)
or maike.bat (Windows systems). They both assume GCC and that it's in your
path. Output: shared.(dll/so), camin(.exe), nmain(.exe).
To run the test: execute either nmain or cmain in a shell window.
To build buy hand:
- build the shared object (shared.nim):
$ nim c shared.nim
- build the client executables:
$ nim c -o:nmain main.nim
$ gcc -o cmain main.c -ldl

View File

@@ -0,0 +1,63 @@
discard """
cmd: "nim $target --debuginfo --hints:on --app:lib $options $file"
"""
import strutils
# Global state, accessing with threads, no locks. Don't do this at
# home.
var gCounter: uint64
var gTxStatus: bool
var gRxStatus: bool
var gConnectStatus: bool
var gPttStatus: bool
var gComm1Status: bool
var gComm2Status: bool
proc getTxStatus(): string =
result = if gTxStatus: "On" else: "Off"
gTxStatus = not gTxStatus
proc getRxStatus(): string =
result = if gRxStatus: "On" else: "Off"
gRxStatus = not gRxStatus
proc getConnectStatus(): string =
result = if gConnectStatus: "Yes" else: "No"
gConnectStatus = not gConnectStatus
proc getPttStatus(): string =
result = if gPttStatus: "PTT: On" else: "PTT: Off"
gPttStatus = not gPttStatus
proc getComm1Status(): string =
result = if gComm1Status: "On" else: "Off"
gComm1Status = not gComm1Status
proc getComm2Status(): string =
result = if gComm2Status: "On" else: "Off"
gComm2Status = not gComm2Status
proc status() {.exportc: "status", dynlib.} =
var tx_status = getTxStatus()
var rx_status = getRxStatus()
var connected = getConnectStatus()
var ptt_status = getPttStatus()
var str1: string = "[PilotEdge] Connected: $1 TX: $2 RX: $3" % [connected, tx_status, rx_status]
var a = getComm1Status()
var b = getComm2Status()
var str2: string = "$1 COM1: $2 COM2: $3" % [ptt_status, a, b]
# echo(str1)
# echo(str2)
proc count() {.exportc: "count", dynlib.} =
var temp: uint64
for i in 0..100_000:
temp += 1
gCounter += 1
# echo("gCounter: ", gCounter)
proc checkOccupiedMem() {.exportc: "checkOccupiedMem", dynlib.} =
if getOccupiedMem() > 10_000_000:
quit 1
discard

View File

@@ -0,0 +1,5 @@
--app:lib
--threads:on
-d:release
-d:useRealtimeGC

View File

@@ -138,6 +138,18 @@ proc gcTests(r: var TResults, cat: Category, options: string) =
test "stackrefleak"
test "cyclecollector"
proc longGCTests(r: var TResults, cat: Category, options: string) =
when defined(windows):
let cOptions = "gcc -ldl -DWIN"
else:
let cOptions = "gcc -ldl"
var c = initResults()
# According to ioTests, this should compile the file
testNoSpec c, makeTest("tests/realtimeGC/shared", options, cat, actionCompile)
testC r, makeTest("tests/realtimeGC/cmain", cOptions, cat, actionRun)
testSpec r, makeTest("tests/realtimeGC/nmain", options & "--threads: on", cat, actionRun)
# ------------------------- threading tests -----------------------------------
proc threadTests(r: var TResults, cat: Category, options: string) =
@@ -340,6 +352,8 @@ proc processCategory(r: var TResults, cat: Category, options: string) =
dllTests(r, cat, options)
of "gc":
gcTests(r, cat, options)
of "longgc":
longGCTests(r, cat, options)
of "debugger":
debuggerTests(r, cat, options)
of "manyloc":

View File

@@ -89,6 +89,25 @@ proc callCompiler(cmdTemplate, filename, options: string,
elif suc =~ pegSuccess:
result.err = reSuccess
proc callCCompiler(cmdTemplate, filename, options: string,
target: TTarget): TSpec =
let c = parseCmdLine(cmdTemplate % ["target", targetToCmd[target],
"options", options, "file", filename.quoteShell])
var p = startProcess(command="gcc", args=c[5.. ^1],
options={poStdErrToStdOut, poUsePath})
let outp = p.outputStream
var x = newStringOfCap(120)
result.nimout = ""
result.msg = ""
result.file = ""
result.outp = ""
result.line = -1
while outp.readLine(x.TaintedString) or running(p):
result.nimout.add(x & "\n")
close(p)
if p.peekExitCode == 0:
result.err = reSuccess
proc initResults: TResults =
result.total = 0
result.passed = 0
@@ -257,8 +276,22 @@ proc testNoSpec(r: var TResults, test: TTest) =
r.addResult(test, "", given.msg, given.err)
if given.err == reSuccess: inc(r.passed)
proc testC(r: var TResults, test: TTest) =
# runs C code. Doesn't support any specs, just goes by exit code.
let tname = test.name.addFileExt(".c")
inc(r.total)
styledEcho "Processing ", fgCyan, extractFilename(tname)
var given = callCCompiler(cmdTemplate, test.name & ".c", test.options, test.target)
if given.err != reSuccess:
r.addResult(test, "", given.msg, given.err)
elif test.action == actionRun:
let exeFile = changeFileExt(test.name, ExeExt)
var (buf, exitCode) = execCmdEx(exeFile, options = {poStdErrToStdOut, poUseShell})
if exitCode != 0: given.err = reExitCodesDiffer
if given.err == reSuccess: inc(r.passed)
proc makeTest(test, options: string, cat: Category, action = actionCompile,
target = targetC): TTest =
target = targetC, env: string = ""): TTest =
# start with 'actionCompile', will be overwritten in the spec:
result = TTest(cat: cat, name: test, options: options,
target: target, action: action)