diff options
author | Alex Waterman <alexw@nvidia.com> | 2018-06-27 17:45:07 -0400 |
---|---|---|
committer | mobile promotions <svcmobile_promotions@nvidia.com> | 2018-08-10 02:11:06 -0400 |
commit | 691bf904451bfe2e4c44ea05319149996abbbbf1 (patch) | |
tree | 0fe66bd37989f9d619234b7f4d2be1df6ed61c85 /userspace/src | |
parent | 6e746a97cc7ee2bc5a3adee04dd9c65b3921eee5 (diff) |
gpu: nvgpu: unit: Add unit testing FW
Full documentation for this is in the unit testing
confluence page.
JIRA NVGPU-525
Bug 2261555
Change-Id: I463e6267eb0eb12b7313f8b275266e8faabe5ccf
Signed-off-by: Alex Waterman <alexw@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/1683915
GVS: Gerrit_Virtual_Submit
Reviewed-by: Konsta Holtta <kholtta@nvidia.com>
Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
Diffstat (limited to 'userspace/src')
-rw-r--r-- | userspace/src/args.c | 134 | ||||
-rw-r--r-- | userspace/src/exec.c | 90 | ||||
-rw-r--r-- | userspace/src/io.c | 105 | ||||
-rw-r--r-- | userspace/src/module.c | 167 | ||||
-rw-r--r-- | userspace/src/nvgpu.c | 78 | ||||
-rw-r--r-- | userspace/src/results.c | 128 | ||||
-rw-r--r-- | userspace/src/unit_main.c | 76 |
7 files changed, 778 insertions, 0 deletions
diff --git a/userspace/src/args.c b/userspace/src/args.c new file mode 100644 index 00000000..d91c6f6e --- /dev/null +++ b/userspace/src/args.c | |||
@@ -0,0 +1,134 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
20 | * DEALINGS IN THE SOFTWARE. | ||
21 | */ | ||
22 | |||
23 | #include <stdio.h> | ||
24 | #include <getopt.h> | ||
25 | #include <stdlib.h> | ||
26 | #include <string.h> | ||
27 | |||
28 | #include <unit/core.h> | ||
29 | #include <unit/args.h> | ||
30 | #include <unit/io.h> | ||
31 | |||
32 | static struct option core_opts[] = { | ||
33 | { "help", 0, NULL, 'h' }, | ||
34 | { "verbose", 0, NULL, 'v' }, | ||
35 | { "quiet", 0, NULL, 'q' }, | ||
36 | { "no-color", 0, NULL, 'C' }, | ||
37 | |||
38 | { "unit-load-path", 1, NULL, 'L' }, | ||
39 | |||
40 | { NULL, 0, NULL, 0 } | ||
41 | }; | ||
42 | |||
43 | static const char *core_opts_str = "hvqCL:"; | ||
44 | |||
45 | void core_print_help(struct unit_fw *fw) | ||
46 | { | ||
47 | const char **line, *help_msg[] = { | ||
48 | "NvGpu Unit Testing FW. Basic usage\n", | ||
49 | "\n", | ||
50 | " $ nvgpu_unit [options] <unit>\n", | ||
51 | "\n", | ||
52 | "Basic usage consists of one or more options and a particular unit test to\n", | ||
53 | "execute.\n", | ||
54 | "\n", | ||
55 | "Available options are as follows:\n", | ||
56 | "\n", | ||
57 | " -h, --help Print this help message and exit.\n", | ||
58 | " -v, --verbose Increment the verbosity level. Can be specified\n", | ||
59 | " multiple times.\n", | ||
60 | " -q, --quiet Set the verbose level back to 0.\n", | ||
61 | " -C, --no-color Disable color printing; for example, if writing\n", | ||
62 | " output to a file the color escape sequences will\n", | ||
63 | " corrupt that file.\n", | ||
64 | " -L, --unit-load-path <PATH>\n", | ||
65 | " Path to where the unit test libraries reside.\n", | ||
66 | "\n", | ||
67 | "Note: mandatory arguments to long arguments are mandatory for short\n", | ||
68 | "arguments as well.\n", | ||
69 | NULL | ||
70 | }; | ||
71 | |||
72 | line = help_msg; | ||
73 | while (*line != NULL) { | ||
74 | core_msg(fw, "%s", *line); | ||
75 | line++; | ||
76 | } | ||
77 | } | ||
78 | |||
79 | static void set_arg_defaults(struct unit_fw_args *args) | ||
80 | { | ||
81 | args->unit_load_path = DEFAULT_ARG_UNIT_LOAD_PATH; | ||
82 | } | ||
83 | |||
84 | /* | ||
85 | * Parse command line arguments. | ||
86 | */ | ||
87 | int core_parse_args(struct unit_fw *fw, int argc, char **argv) | ||
88 | { | ||
89 | int c, opt_index; | ||
90 | struct unit_fw_args *args; | ||
91 | |||
92 | args = malloc(sizeof(*args)); | ||
93 | if (!args) | ||
94 | return -1; | ||
95 | |||
96 | memset(args, 0, sizeof(*args)); | ||
97 | set_arg_defaults(args); | ||
98 | |||
99 | fw->args = args; | ||
100 | |||
101 | while (1) { | ||
102 | c = getopt_long(argc, argv, | ||
103 | core_opts_str, core_opts, &opt_index); | ||
104 | |||
105 | if (c == -1) | ||
106 | break; | ||
107 | |||
108 | switch (c) { | ||
109 | case 'h': | ||
110 | args->help = true; | ||
111 | break; | ||
112 | case 'v': | ||
113 | args->verbose_lvl += 1; | ||
114 | break; | ||
115 | case 'q': | ||
116 | args->verbose_lvl = 0; | ||
117 | break; | ||
118 | case 'C': | ||
119 | args->no_color = true; | ||
120 | break; | ||
121 | case 'L': | ||
122 | args->unit_load_path = optarg; | ||
123 | break; | ||
124 | case '?': | ||
125 | args->help = true; | ||
126 | return -1; | ||
127 | default: | ||
128 | core_err(fw, "bug?!\n"); | ||
129 | return -1; | ||
130 | } | ||
131 | } | ||
132 | |||
133 | return 0; | ||
134 | } | ||
diff --git a/userspace/src/exec.c b/userspace/src/exec.c new file mode 100644 index 00000000..b9ba1336 --- /dev/null +++ b/userspace/src/exec.c | |||
@@ -0,0 +1,90 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
20 | * DEALINGS IN THE SOFTWARE. | ||
21 | */ | ||
22 | |||
23 | #include <stdlib.h> | ||
24 | |||
25 | #include <unit/io.h> | ||
26 | #include <unit/core.h> | ||
27 | #include <unit/unit.h> | ||
28 | #include <unit/module.h> | ||
29 | #include <unit/results.h> | ||
30 | |||
31 | #include <nvgpu/posix/probe.h> | ||
32 | |||
33 | /* | ||
34 | * Execute a module and all its subtests. This function builds a gk20a for the | ||
35 | * test to use by executing nvgpu_posix_probe() and nvgpu_posix_cleanup(); | ||
36 | */ | ||
37 | static int core_exec_module(struct unit_fw *fw, | ||
38 | struct unit_module *module) | ||
39 | { | ||
40 | unsigned int i; | ||
41 | struct gk20a *g = fw->nvgpu.nvgpu_posix_probe(); | ||
42 | |||
43 | if (!g) | ||
44 | return -1; | ||
45 | |||
46 | core_vbs(fw, 1, "Execing module: %s\n", module->name); | ||
47 | |||
48 | /* | ||
49 | * Execute each test within the module. No reinit is done between tests. | ||
50 | * Thats up to the module itself to handle. Any setup/teardown between | ||
51 | * unit tests must be handled within the module. | ||
52 | */ | ||
53 | for (i = 0; i < module->nr_tests; i++) { | ||
54 | struct unit_module_test *t = module->tests + i; | ||
55 | int test_status; | ||
56 | |||
57 | core_msg(fw, "Running %s.%s\n", module->name, t->name); | ||
58 | test_status = t->fn(module, g, t->args); | ||
59 | |||
60 | if (test_status != UNIT_SUCCESS) | ||
61 | core_msg_color(fw, C_RED, | ||
62 | " Unit error! Test %s.%s FAILED!\n", | ||
63 | module->name, t->name); | ||
64 | |||
65 | core_add_test_record(fw, module, t, | ||
66 | test_status == UNIT_SUCCESS); | ||
67 | } | ||
68 | |||
69 | fw->nvgpu.nvgpu_posix_cleanup(g); | ||
70 | |||
71 | return 0; | ||
72 | } | ||
73 | |||
74 | /* | ||
75 | * Execute all modules loaded by the unit test framework. | ||
76 | */ | ||
77 | int core_exec(struct unit_fw *fw) | ||
78 | { | ||
79 | int ret; | ||
80 | struct unit_module **modules; | ||
81 | |||
82 | for (modules = fw->modules; *modules != NULL; modules++) { | ||
83 | ret = core_exec_module(fw, *modules); | ||
84 | |||
85 | if (ret != 0) | ||
86 | return ret; | ||
87 | } | ||
88 | |||
89 | return 0; | ||
90 | } | ||
diff --git a/userspace/src/io.c b/userspace/src/io.c new file mode 100644 index 00000000..21ac54da --- /dev/null +++ b/userspace/src/io.c | |||
@@ -0,0 +1,105 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
20 | * DEALINGS IN THE SOFTWARE. | ||
21 | */ | ||
22 | |||
23 | #include <stdio.h> | ||
24 | #include <stdarg.h> | ||
25 | #include <string.h> | ||
26 | |||
27 | #include <unit/io.h> | ||
28 | #include <unit/args.h> | ||
29 | #include <unit/core.h> | ||
30 | #include <unit/unit.h> | ||
31 | |||
32 | #define MAX_LOG_LINE_LENGTH 4096 | ||
33 | |||
34 | static void __core_print_file(struct unit_fw *fw, FILE *filp, | ||
35 | const char *prefix, const char *msg, | ||
36 | const char *color) | ||
37 | { | ||
38 | if (color == NULL || args(fw)->no_color) | ||
39 | color = ""; | ||
40 | |||
41 | fprintf(filp, "[%s%s%s] %s%s%s", | ||
42 | color, prefix, C_RESET, | ||
43 | color, msg, C_RESET); | ||
44 | } | ||
45 | |||
46 | __attribute__((format (printf, 3, 4))) | ||
47 | void __core_print_stdout(struct unit_fw *fw, const char *color, | ||
48 | const char *fmt, ...) | ||
49 | { | ||
50 | va_list args; | ||
51 | char buf[MAX_LOG_LINE_LENGTH]; | ||
52 | |||
53 | va_start(args, fmt); | ||
54 | vsnprintf(buf, MAX_LOG_LINE_LENGTH, fmt, args); | ||
55 | va_end(args); | ||
56 | |||
57 | buf[MAX_LOG_LINE_LENGTH - 1] = 0; | ||
58 | |||
59 | __core_print_file(fw, stdout, "C", buf, color); | ||
60 | } | ||
61 | |||
62 | __attribute__((format (printf, 2, 3))) | ||
63 | void __core_print_stderr(struct unit_fw *fw, const char *fmt, ...) | ||
64 | { | ||
65 | va_list args; | ||
66 | char buf[MAX_LOG_LINE_LENGTH]; | ||
67 | |||
68 | va_start(args, fmt); | ||
69 | vsnprintf(buf, MAX_LOG_LINE_LENGTH, fmt, args); | ||
70 | va_end(args); | ||
71 | |||
72 | buf[MAX_LOG_LINE_LENGTH - 1] = 0; | ||
73 | |||
74 | __core_print_file(fw, stdout, "E", buf, C_RED); | ||
75 | } | ||
76 | |||
77 | __attribute__((format (printf, 3, 4))) | ||
78 | void __unit_info_color(struct unit_module *unit, const char *color, | ||
79 | const char *fmt, ...) | ||
80 | { | ||
81 | va_list args; | ||
82 | char buf[MAX_LOG_LINE_LENGTH]; | ||
83 | char *msg_start; | ||
84 | int written; | ||
85 | |||
86 | /* | ||
87 | * Default color for module prints is blue. Users can still turn this | ||
88 | * off with '-C'. | ||
89 | */ | ||
90 | if (color == NULL) | ||
91 | color = C_BLUE; | ||
92 | |||
93 | /* | ||
94 | * First prepend the unit name to the print. | ||
95 | */ | ||
96 | written = snprintf(buf, MAX_LOG_LINE_LENGTH, " [%s] ", unit->name); | ||
97 | |||
98 | msg_start = buf + written; | ||
99 | |||
100 | va_start(args, fmt); | ||
101 | vsnprintf(msg_start, MAX_LOG_LINE_LENGTH - written, fmt, args); | ||
102 | va_end(args); | ||
103 | |||
104 | __core_print_file(unit->fw, stdout, "T", buf, color); | ||
105 | } | ||
diff --git a/userspace/src/module.c b/userspace/src/module.c new file mode 100644 index 00000000..c111c6cb --- /dev/null +++ b/userspace/src/module.c | |||
@@ -0,0 +1,167 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
20 | * DEALINGS IN THE SOFTWARE. | ||
21 | */ | ||
22 | |||
23 | #include <errno.h> | ||
24 | #include <dlfcn.h> | ||
25 | #include <dirent.h> | ||
26 | #include <string.h> | ||
27 | #include <stdlib.h> | ||
28 | |||
29 | #include <sys/types.h> | ||
30 | |||
31 | #include <unit/core.h> | ||
32 | #include <unit/io.h> | ||
33 | #include <unit/args.h> | ||
34 | #include <unit/unit.h> | ||
35 | |||
36 | static int check_module(struct unit_fw *fw, struct unit_module *mod) | ||
37 | { | ||
38 | unsigned int i; | ||
39 | |||
40 | /* | ||
41 | * Make sure this module has reasonable data. | ||
42 | */ | ||
43 | if (mod->name == NULL) { | ||
44 | core_err(fw, "Unnamed module!"); | ||
45 | return -1; | ||
46 | } | ||
47 | |||
48 | if (mod->tests == NULL || mod->nr_tests == 0) { | ||
49 | core_err(fw, "%s: Empty module!\n", mod->name); | ||
50 | return -1; | ||
51 | } | ||
52 | |||
53 | for (i = 0; i < mod->nr_tests; i++) { | ||
54 | struct unit_module_test *test = &mod->tests[i]; | ||
55 | |||
56 | if (test->name == NULL) { | ||
57 | core_err(fw, "%s: Unnamed test\n", mod->name); | ||
58 | return -1; | ||
59 | } | ||
60 | |||
61 | if (test->fn == NULL) { | ||
62 | core_err(fw, "%s: Test %s missing function \n", | ||
63 | mod->name, test->name); | ||
64 | return -1; | ||
65 | } | ||
66 | } | ||
67 | |||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | static struct unit_module *load_one_module(struct unit_fw *fw, | ||
72 | struct dirent *dent) | ||
73 | { | ||
74 | void *lib_handle; | ||
75 | struct unit_module *mod; | ||
76 | |||
77 | core_vbs(fw, 1, "Loading: %s\n", dent->d_name); | ||
78 | |||
79 | lib_handle = dlopen(dent->d_name, RTLD_NOW); | ||
80 | if (lib_handle == NULL) { | ||
81 | core_err(fw, "Failed to load %s: %s\n", | ||
82 | dent->d_name, dlerror()); | ||
83 | return NULL; | ||
84 | } | ||
85 | |||
86 | mod = dlsym(lib_handle, "__unit_module__"); | ||
87 | if (mod == NULL) { | ||
88 | core_vbs(fw, 1, | ||
89 | "Failed to resolve __unit_module__ in %s: %s\n", | ||
90 | dent->d_name, dlerror()); | ||
91 | return NULL; | ||
92 | } | ||
93 | |||
94 | mod->lib_handle = lib_handle; | ||
95 | mod->fw = fw; | ||
96 | |||
97 | core_vbs(fw, 1, " '%s' contains %lu tests\n", mod->name, mod->nr_tests); | ||
98 | |||
99 | return mod; | ||
100 | } | ||
101 | |||
102 | /* | ||
103 | * Load all the modules we can from the module load path. Return the list of | ||
104 | * loaded module as an array of pointers to modules. The returned list of | ||
105 | * modules is NULL terminated. | ||
106 | */ | ||
107 | struct unit_module **core_load_modules(struct unit_fw *fw) | ||
108 | { | ||
109 | int nr_modules = 0, i; | ||
110 | DIR *load_dir; | ||
111 | struct dirent *ent; | ||
112 | const char *load_path = args(fw)->unit_load_path; | ||
113 | struct unit_module **modules, *mod; | ||
114 | |||
115 | core_vbs(fw, 1, "Loading modules from %s\n", load_path); | ||
116 | |||
117 | /* | ||
118 | * Open and count the number of files in the dir. | ||
119 | */ | ||
120 | load_dir = opendir(load_path); | ||
121 | if (!load_dir) { | ||
122 | core_err(fw, "%s: Unable to open dir (%s)\n", | ||
123 | load_path, strerror(errno)); | ||
124 | return NULL; | ||
125 | } | ||
126 | |||
127 | while (readdir(load_dir) != NULL) | ||
128 | nr_modules += 1; | ||
129 | |||
130 | /* '.' and '..' should be skipped. */ | ||
131 | nr_modules -= 2; | ||
132 | |||
133 | /* | ||
134 | * Now allocate necessary space for storing pointers to the modules and | ||
135 | * load the modules. +1 for the last NULL entry. | ||
136 | */ | ||
137 | modules = malloc(sizeof(*modules) * (nr_modules + 1)); | ||
138 | if (!modules) { | ||
139 | core_err(fw, "Out of mem! (huh?)\n"); | ||
140 | goto err; | ||
141 | } | ||
142 | |||
143 | rewinddir(load_dir); | ||
144 | i = 0; | ||
145 | while ((ent = readdir(load_dir)) != NULL) { | ||
146 | if (strcmp(".", ent->d_name) == 0 || | ||
147 | strcmp("..", ent->d_name) == 0) | ||
148 | continue; | ||
149 | |||
150 | mod = load_one_module(fw, ent); | ||
151 | if (mod == NULL) | ||
152 | continue; | ||
153 | |||
154 | if (check_module(fw, mod) != 0) | ||
155 | continue; | ||
156 | |||
157 | modules[i] = mod; | ||
158 | i++; | ||
159 | } | ||
160 | |||
161 | modules[i] = NULL; | ||
162 | return modules; | ||
163 | |||
164 | err: | ||
165 | closedir(load_dir); | ||
166 | return NULL; | ||
167 | } | ||
diff --git a/userspace/src/nvgpu.c b/userspace/src/nvgpu.c new file mode 100644 index 00000000..a9b7ced3 --- /dev/null +++ b/userspace/src/nvgpu.c | |||
@@ -0,0 +1,78 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
20 | * DEALINGS IN THE SOFTWARE. | ||
21 | */ | ||
22 | |||
23 | #include <dlfcn.h> | ||
24 | #include <stdlib.h> | ||
25 | |||
26 | #include <unit/io.h> | ||
27 | #include <unit/core.h> | ||
28 | |||
29 | /* | ||
30 | * Load libnvgpu-drv.so. This is done with dlopen() since this will make | ||
31 | * resolving addresses into symbols easier in the future. | ||
32 | * | ||
33 | * Also, this makes people think carefully about what functions to call in | ||
34 | * nvgpu-drv from the unit test FW. The interaction should really be limited | ||
35 | * and doing explicit name lookups is a good way to prevent too much coupling. | ||
36 | */ | ||
37 | int core_load_nvgpu(struct unit_fw *fw) | ||
38 | { | ||
39 | const char *msg; | ||
40 | |||
41 | /* | ||
42 | * Specify a GLOBAL binding so that subsequently loaded unit tests see | ||
43 | * the nvgpu-drv library. They will of course need it (and will access | ||
44 | * it directly). I.e they will link against nvgpu-drv and this should | ||
45 | * satisfy that linkage. | ||
46 | */ | ||
47 | fw->nvgpu_so = dlopen("libnvgpu-drv.so", RTLD_NOW | RTLD_GLOBAL); | ||
48 | |||
49 | if (fw->nvgpu_so == NULL) { | ||
50 | msg = dlerror(); | ||
51 | core_err(fw, "Failed to load nvgpu-drv: %s\n", msg); | ||
52 | return -1; | ||
53 | } | ||
54 | |||
55 | /* | ||
56 | * We directly check the value of the returned symbol for these | ||
57 | * functions against NULL because if it is NULL then something is | ||
58 | * terribly wrong. | ||
59 | */ | ||
60 | |||
61 | fw->nvgpu.nvgpu_posix_probe = dlsym(fw->nvgpu_so, | ||
62 | "nvgpu_posix_probe"); | ||
63 | if (fw->nvgpu.nvgpu_posix_probe == NULL) { | ||
64 | msg = dlerror(); | ||
65 | core_err(fw, "Failed to resolve nvgpu_posix_probe: %s\n", msg); | ||
66 | return -1; | ||
67 | } | ||
68 | |||
69 | fw->nvgpu.nvgpu_posix_cleanup = dlsym(fw->nvgpu_so, | ||
70 | "nvgpu_posix_cleanup"); | ||
71 | if (fw->nvgpu.nvgpu_posix_cleanup == NULL) { | ||
72 | msg = dlerror(); | ||
73 | core_err(fw, "Failed to resolve nvgpu_posix_cleanup: %s\n", msg); | ||
74 | return -1; | ||
75 | } | ||
76 | |||
77 | return 0; | ||
78 | } | ||
diff --git a/userspace/src/results.c b/userspace/src/results.c new file mode 100644 index 00000000..ae077b82 --- /dev/null +++ b/userspace/src/results.c | |||
@@ -0,0 +1,128 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
20 | * DEALINGS IN THE SOFTWARE. | ||
21 | */ | ||
22 | |||
23 | #include <stdlib.h> | ||
24 | #include <string.h> | ||
25 | |||
26 | #include <unit/io.h> | ||
27 | #include <unit/core.h> | ||
28 | #include <unit/unit.h> | ||
29 | #include <unit/results.h> | ||
30 | |||
31 | static int __init_results(struct unit_fw *fw) | ||
32 | { | ||
33 | struct unit_results *results; | ||
34 | |||
35 | if (fw->results != NULL) | ||
36 | return 0; | ||
37 | |||
38 | results = malloc(sizeof(*results)); | ||
39 | if (results == NULL) | ||
40 | return -1; | ||
41 | |||
42 | memset(results, 0, sizeof(*results)); | ||
43 | |||
44 | fw->results = results; | ||
45 | |||
46 | return 0; | ||
47 | } | ||
48 | |||
49 | static void add_record(struct unit_test_list *list, | ||
50 | struct unit_test_record *tr) | ||
51 | { | ||
52 | /* | ||
53 | * First entry. | ||
54 | */ | ||
55 | if (list->head == NULL) { | ||
56 | list->head = tr; | ||
57 | list->last = tr; | ||
58 | return; | ||
59 | } | ||
60 | |||
61 | /* | ||
62 | * Add to the end of the list and update the pointer to the last entry | ||
63 | * in the list. This gives us O(1) add time. | ||
64 | */ | ||
65 | list->last->next = tr; | ||
66 | list->last = tr; | ||
67 | } | ||
68 | |||
69 | int core_add_test_record(struct unit_fw *fw, | ||
70 | struct unit_module *mod, | ||
71 | struct unit_module_test *test, | ||
72 | bool success) | ||
73 | { | ||
74 | struct unit_test_record *tr; | ||
75 | |||
76 | /* | ||
77 | * Dones nothing if results are already inited. | ||
78 | */ | ||
79 | if (__init_results(fw) != 0) | ||
80 | return -1; | ||
81 | |||
82 | tr = malloc(sizeof(*tr)); | ||
83 | if (tr == NULL) | ||
84 | return -1; | ||
85 | |||
86 | tr->mod = mod; | ||
87 | tr->test = test; | ||
88 | tr->status = success; | ||
89 | tr->next = NULL; | ||
90 | |||
91 | if (success) | ||
92 | add_record(&fw->results->passing, tr); | ||
93 | else | ||
94 | add_record(&fw->results->failing, tr); | ||
95 | |||
96 | fw->results->nr_tests += 1; | ||
97 | if (success) | ||
98 | fw->results->nr_passing += 1; | ||
99 | |||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | void core_print_test_status(struct unit_fw *fw) | ||
104 | { | ||
105 | struct unit_test_list *failing_tests = &fw->results->failing; | ||
106 | struct unit_test_record *rec; | ||
107 | |||
108 | /* | ||
109 | * Print stats for the tests. | ||
110 | */ | ||
111 | core_msg(fw, "\n"); | ||
112 | core_msg(fw, "Test results:\n"); | ||
113 | core_msg(fw, "-------------\n"); | ||
114 | core_msg(fw, "\n"); | ||
115 | core_msg(fw, " Passing: %d\n", fw->results->nr_passing); | ||
116 | core_msg(fw, " Failing: %d\n", | ||
117 | fw->results->nr_tests - fw->results->nr_passing); | ||
118 | core_msg(fw, " Total: %d\n", fw->results->nr_tests); | ||
119 | core_msg(fw, "\n"); | ||
120 | core_msg(fw, "Failing tests:\n"); | ||
121 | core_msg(fw, "\n"); | ||
122 | |||
123 | for_record_in_test_list(failing_tests, rec) { | ||
124 | core_msg(fw, " %s.%s\n", | ||
125 | rec->mod->name, | ||
126 | rec->test->name); | ||
127 | } | ||
128 | } | ||
diff --git a/userspace/src/unit_main.c b/userspace/src/unit_main.c new file mode 100644 index 00000000..31c31d50 --- /dev/null +++ b/userspace/src/unit_main.c | |||
@@ -0,0 +1,76 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
20 | * DEALINGS IN THE SOFTWARE. | ||
21 | */ | ||
22 | |||
23 | /** | ||
24 | * NvGpu unit testing framework! | ||
25 | */ | ||
26 | |||
27 | #include <stdlib.h> | ||
28 | #include <string.h> | ||
29 | |||
30 | #include <unit/io.h> | ||
31 | #include <unit/core.h> | ||
32 | #include <unit/args.h> | ||
33 | #include <unit/module.h> | ||
34 | #include <unit/results.h> | ||
35 | |||
36 | int main(int argc, char **argv) | ||
37 | { | ||
38 | struct unit_fw *fw; | ||
39 | int ret; | ||
40 | |||
41 | fw = malloc(sizeof(*fw)); | ||
42 | if (!fw) | ||
43 | return 1; | ||
44 | |||
45 | memset(fw, 0, sizeof(*fw)); | ||
46 | |||
47 | ret = core_parse_args(fw, argc, argv); | ||
48 | if (ret) { | ||
49 | core_err(fw, "Enable to parse args.\n"); | ||
50 | core_err(fw, "Exiting!\n"); | ||
51 | return 1; | ||
52 | } | ||
53 | |||
54 | core_vbs(fw, 1, "Welcome to the nvgpu unit testing framework!\n"); | ||
55 | |||
56 | if (args(fw)->help) { | ||
57 | core_print_help(fw); | ||
58 | return 1; | ||
59 | } | ||
60 | |||
61 | ret = core_load_nvgpu(fw); | ||
62 | if (ret != 0) | ||
63 | return ret; | ||
64 | |||
65 | fw->modules = core_load_modules(fw); | ||
66 | if (fw->modules == NULL) | ||
67 | return -1; | ||
68 | |||
69 | ret = core_exec(fw); | ||
70 | if (ret != 0) | ||
71 | return ret; | ||
72 | |||
73 | core_print_test_status(fw); | ||
74 | |||
75 | return 0; | ||
76 | } | ||