mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-30 01:44:37 +00:00
Merge pull request #2564 from reactormonk/jpoirier-realtimeGCTest
Jpoirier realtime gc test
This commit is contained in:
@@ -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
67
tests/realtimeGC/cmain.c
Normal 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;
|
||||
}
|
||||
6
tests/realtimeGC/main.nim.cfg
Normal file
6
tests/realtimeGC/main.nim.cfg
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
--app:console
|
||||
--threads:on
|
||||
|
||||
-d:release
|
||||
-d:useRealtimeGC
|
||||
46
tests/realtimeGC/nmain.nim
Normal file
46
tests/realtimeGC/nmain.nim
Normal 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()
|
||||
21
tests/realtimeGC/readme.txt
Normal file
21
tests/realtimeGC/readme.txt
Normal 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
|
||||
63
tests/realtimeGC/shared.nim
Normal file
63
tests/realtimeGC/shared.nim
Normal 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
|
||||
5
tests/realtimeGC/shared.nim.cfg
Normal file
5
tests/realtimeGC/shared.nim.cfg
Normal file
@@ -0,0 +1,5 @@
|
||||
--app:lib
|
||||
--threads:on
|
||||
|
||||
-d:release
|
||||
-d:useRealtimeGC
|
||||
@@ -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":
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user