Skip to content

Commit 487149f

Browse files
authored
Merge pull request #552 from ChinYikMing/feat/logging-api
Standardize logging utility
2 parents 6e6cfb8 + 85701c4 commit 487149f

16 files changed

+339
-111
lines changed

Makefile

Lines changed: 37 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ $(call set-feature, MOP_FUSION)
2828
ENABLE_BLOCK_CHAINING ?= 1
2929
$(call set-feature, BLOCK_CHAINING)
3030

31+
# Enable logging with color
32+
ENABLE_LOG_COLOR ?= 1
33+
$(call set-feature, LOG_COLOR)
34+
3135
# Enable system emulation
3236
ENABLE_SYSTEM ?= 0
3337
$(call set-feature, SYSTEM)
@@ -293,6 +297,7 @@ OBJS := \
293297
syscall.o \
294298
emulate.o \
295299
riscv.o \
300+
log.o \
296301
elf.o \
297302
cache.o \
298303
mpool.o \
@@ -347,54 +352,48 @@ EXPECTED_puzzle = success in 2005 trials
347352
EXPECTED_fcalc = Performed 12 tests, 0 failures, 100% success rate.
348353
EXPECTED_pi = 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086
349354

355+
LOG_FILTER=sed -E '/^[0-9]{2}:[0-9]{2}:[0-9]{2} /d'
356+
357+
define exec
358+
$(eval OUTPUT_FILE := $(shell mktemp))
359+
$(eval _ := $(shell LC_ALL=C $(BIN) $(1) $(2) > $(OUTPUT_FILE)))
360+
$(eval RC := $(.SHELLSTATUS))
361+
endef
362+
363+
# $(1): rv32emu's extra CLI parameter
364+
# $(2): ELF executable
365+
# $(3): ELF executable name
366+
# $(4): extra command in the pipeline
367+
# $(5): expected output
368+
define check-test
369+
$(call exec, $(1), $(2))
370+
$(Q)$(PRINTF) "Running $(3) ... "; \
371+
if [ 0 -eq $(RC) ] && [ "$(strip $(shell cat $(OUTPUT_FILE) | $(LOG_FILTER) | $(4)))" = "$(strip $(5))" ]; then \
372+
$(call notice, [OK]); \
373+
else \
374+
$(PRINTF) "Failed.\n"; \
375+
exit 1; \
376+
fi; \
377+
$(RM) $(OUTPUT_FILE)
378+
endef
379+
350380
check-hello: $(BIN)
351-
$(Q)$(PRINTF) "Running hello.elf ... "; \
352-
if [ "$(shell LC_ALL=C $(BIN) $(OUT)/hello.elf | uniq)" = "$(strip $(EXPECTED_hello)) inferior exit code 0" ]; then \
353-
$(call notice, [OK]); \
354-
else \
355-
$(PRINTF) "Failed.\n"; \
356-
exit 1; \
357-
fi;
381+
$(call check-test, , $(OUT)/hello.elf, hello.elf, uniq, $(EXPECTED_hello))
358382

359383
check: $(BIN) check-hello artifact
360-
$(Q)$(foreach e,$(CHECK_ELF_FILES),\
361-
$(PRINTF) "Running $(e) ... "; \
362-
if [ "$(shell LC_ALL=C $(BIN) $(OUT)/riscv32/$(e) | uniq)" = "$(strip $(EXPECTED_$(e))) inferior exit code 0" ]; then \
363-
$(call notice, [OK]); \
364-
else \
365-
$(PRINTF) "Failed.\n"; \
366-
exit 1; \
367-
fi; \
368-
)
369-
370-
EXPECTED_aes_sha1 = 1242a6757c8aef23e50b5264f5941a2f4b4a347e -
384+
$(Q)$(foreach e, $(CHECK_ELF_FILES), $(call check-test, , $(OUT)/riscv32/$(e), $(e), uniq, $(EXPECTED_$(e))))
385+
386+
EXPECTED_aes_sha1 = 89169ec034bec1c6bb2c556b26728a736d350ca3 -
371387
misalign: $(BIN) artifact
372-
$(Q)$(PRINTF) "Running uaes ... ";
373-
$(Q)if [ "$(shell LC_ALL=C $(BIN) -m $(OUT)/riscv32/uaes | $(SHA1SUM))" = "$(EXPECTED_aes_sha1)" ]; then \
374-
$(call notice, [OK]); \
375-
else \
376-
$(PRINTF) "Failed.\n"; \
377-
fi
388+
$(call check-test, -m, $(OUT)/riscv32/uaes, uaes.elf, $(SHA1SUM), $(EXPECTED_aes_sha1))
378389

379390
EXPECTED_misalign = MISALIGNED INSTRUCTION FETCH TEST PASSED!
380391
misalign-in-blk-emu: $(BIN)
381-
$(Q)$(PRINTF) "Running misalign.elf ... "; \
382-
if [ "$(shell LC_ALL=C $(BIN) tests/system/alignment/misalign.elf | tail -n 2)" = "$(strip $(EXPECTED_misalign)) inferior exit code 0" ]; then \
383-
$(call notice, [OK]); \
384-
else \
385-
$(PRINTF) "Failed.\n"; \
386-
exit 1; \
387-
fi;
392+
$(call check-test, , tests/system/alignment/misalign.elf, misalign.elf, tail -n 1, $(EXPECTED_misalign))
388393

389394
EXPECTED_mmu = STORE PAGE FAULT TEST PASSED!
390395
mmu-test: $(BIN)
391-
$(Q)$(PRINTF) "Running vm.elf ... "; \
392-
if [ "$(shell LC_ALL=C $(BIN) tests/system/mmu/vm.elf | tail -n 2)" = "$(strip $(EXPECTED_mmu)) inferior exit code 0" ]; then \
393-
$(call notice, [OK]); \
394-
else \
395-
$(PRINTF) "Failed.\n"; \
396-
exit 1; \
397-
fi;
396+
$(call check-test, , tests/system/mmu/vm.elf, vm.elf, tail -n 1, $(EXPECTED_mmu))
398397

399398
# Non-trivial demonstration programs
400399
ifeq ($(call has, SDL), 1)

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ The image containing all the necessary tools for development and testing can be
155155
* `ENABLE_SYSTEM`: Experimental system emulation, allowing booting Linux kernel. To enable this feature, additional features must also be enabled. However, by default, when `ENABLE_SYSTEM` is enabled, CSR, fence, integer multiplication/division, and atomic Instructions are automatically enabled
156156
* `ENABLE_MOP_FUSION` : Macro-operation fusion
157157
* `ENABLE_BLOCK_CHAINING` : Block chaining of translated blocks
158+
* `ENABLE_LOG_COLOR` : Logging with colors (default)
158159

159160
e.g., run `make ENABLE_EXT_F=0` for the build without floating-point support.
160161

src/common.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <stdint.h>
1010

1111
#include "feature.h"
12+
#include "log.h"
1213

1314
#if defined(__GNUC__) || defined(__clang__)
1415
#define UNUSED __attribute__((unused))

src/devices/uart.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ void u8250_check_ready(u8250_state_t *uart)
4747
static void u8250_handle_out(u8250_state_t *uart, uint8_t value)
4848
{
4949
if (write(uart->out_fd, &value, 1) < 1)
50-
fprintf(stderr, "failed to write UART output: %s\n", strerror(errno));
50+
rv_log_error("Failed to write UART output: %s", strerror(errno));
5151
}
5252

5353
static uint8_t u8250_handle_in(u8250_state_t *uart)
@@ -58,13 +58,13 @@ static uint8_t u8250_handle_in(u8250_state_t *uart)
5858
return value;
5959

6060
if (read(uart->in_fd, &value, 1) < 0)
61-
fprintf(stderr, "failed to read UART input: %s\n", strerror(errno));
61+
rv_log_error("Failed to read UART input: %s", strerror(errno));
6262
uart->in_ready = false;
6363
u8250_check_ready(uart);
6464

6565
if (value == 1) { /* start of heading (Ctrl-a) */
6666
if (getchar() == 120) { /* keyboard x */
67-
printf("\n"); /* end emulator with newline */
67+
rv_log_info("RISC-V emulator is destroyed");
6868
exit(EXIT_SUCCESS);
6969
}
7070
}

src/devices/virtio-blk.c

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ static int virtio_blk_desc_handler(virtio_blk_state_t *vblk,
190190
virtio_blk_write_handler(vblk, sector, vq_desc[1].addr, vq_desc[1].len);
191191
break;
192192
default:
193-
fprintf(stderr, "unsupported virtio-blk operation!\n");
193+
rv_log_error("Unsupported virtio-blk operation");
194194
*status = VIRTIO_BLK_S_UNSUPP;
195195
return -1;
196196
}
@@ -215,7 +215,7 @@ static void virtio_queue_notify_handler(virtio_blk_state_t *vblk, int index)
215215
/* Check for new buffers */
216216
uint16_t new_avail = ram[queue->queue_avail] >> 16;
217217
if (new_avail - queue->last_avail > (uint16_t) queue->queue_num) {
218-
fprintf(stderr, "size check fail\n");
218+
rv_log_error("Size check fail");
219219
return virtio_blk_set_fail(vblk);
220220
}
221221

@@ -374,9 +374,8 @@ void virtio_blk_write(virtio_blk_state_t *vblk, uint32_t addr, uint32_t value)
374374
uint32_t *virtio_blk_init(virtio_blk_state_t *vblk, char *disk_file)
375375
{
376376
if (vblk_dev_cnt >= VBLK_DEV_CNT_MAX) {
377-
fprintf(stderr,
378-
"Exceeded the number of virtio-blk devices that can be "
379-
"allocated.\n");
377+
rv_log_error(
378+
"Exceeded the number of virtio-blk devices that can be allocated");
380379
exit(EXIT_FAILURE);
381380
}
382381

@@ -394,7 +393,7 @@ uint32_t *virtio_blk_init(virtio_blk_state_t *vblk, char *disk_file)
394393
/* Open disk file */
395394
int disk_fd = open(disk_file, O_RDWR);
396395
if (disk_fd < 0) {
397-
fprintf(stderr, "could not open %s\n", disk_file);
396+
rv_log_error("Could not open %s", disk_file);
398397
exit(EXIT_FAILURE);
399398
}
400399

@@ -408,16 +407,12 @@ uint32_t *virtio_blk_init(virtio_blk_state_t *vblk, char *disk_file)
408407
#if HAVE_MMAP
409408
disk_mem = mmap(NULL, VBLK_PRIV(vblk)->disk_size, PROT_READ | PROT_WRITE,
410409
MAP_SHARED, disk_fd, 0);
411-
if (disk_mem == MAP_FAILED) {
412-
fprintf(stderr, "Could not map disk\n");
413-
return NULL;
414-
}
410+
if (disk_mem == MAP_FAILED)
411+
goto err;
415412
#else
416413
disk_mem = malloc(VBLK_PRIV(vblk)->disk_size);
417-
if (!disk_mem) {
418-
fprintf(stderr, "Could not map disk\n");
419-
return NULL;
420-
}
414+
if (!disk_mem)
415+
goto err;
421416
#endif
422417
assert(!(((uintptr_t) disk_mem) & 0b11));
423418
close(disk_fd);
@@ -427,6 +422,10 @@ uint32_t *virtio_blk_init(virtio_blk_state_t *vblk, char *disk_file)
427422
(VBLK_PRIV(vblk)->disk_size - 1) / DISK_BLK_SIZE + 1;
428423

429424
return disk_mem;
425+
426+
err:
427+
rv_log_error("Could not map disk %s", disk_file);
428+
return NULL;
430429
}
431430

432431
virtio_blk_state_t *vblk_new()

src/emulate.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1131,7 +1131,6 @@ void rv_step(void *arg)
11311131

11321132
#ifdef __EMSCRIPTEN__
11331133
if (rv_has_halted(rv)) {
1134-
printf("inferior exit code %d\n", attr->exit_code);
11351134
emscripten_cancel_main_loop();
11361135
rv_delete(rv); /* clean up and reuse memory */
11371136
}
@@ -1346,7 +1345,7 @@ void dump_registers(riscv_t *rv, char *out_file_path)
13461345
{
13471346
FILE *f = out_file_path[0] == '-' ? stdout : fopen(out_file_path, "w");
13481347
if (!f) {
1349-
fprintf(stderr, "Cannot open registers output file.\n");
1348+
rv_log_error("Cannot open registers output file");
13501349
return;
13511350
}
13521351

src/feature.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,5 +108,10 @@
108108
#define RV32_FEATURE_BLOCK_CHAINING 1
109109
#endif
110110

111+
/* Logging with color */
112+
#ifndef RV32_FEATURE_LOG_COLOR
113+
#define RV32_FEATURE_LOG_COLOR 1
114+
#endif
115+
111116
/* Feature test macro */
112117
#define RV32_HAS(x) RV32_FEATURE_##x

src/log.c

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/*
2+
* Copyright (c) 2020 rxi
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a copy
5+
* of this software and associated documentation files (the "Software"), to
6+
* deal in the Software without restriction, including without limitation the
7+
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8+
* sell copies of the Software, and to permit persons to whom the Software is
9+
* 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 THE
17+
* 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 DEALINGS
20+
* IN THE SOFTWARE.
21+
*/
22+
23+
#include "log.h"
24+
25+
static struct {
26+
void *udata;
27+
log_lock_func_t lock;
28+
int level;
29+
bool quiet;
30+
} L;
31+
32+
static const char *level_strings[] = {
33+
"TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL",
34+
};
35+
36+
#if RV32_HAS(LOG_COLOR)
37+
static const char *level_colors[] = {
38+
"\x1b[94m", "\x1b[36m", "\x1b[32m", "\x1b[33m", "\x1b[31m", "\x1b[35m",
39+
};
40+
#endif /* RV32_HAS(LOG_COLOR) */
41+
42+
static void stdout_callback(log_event_t *ev)
43+
{
44+
char buf[16];
45+
buf[strftime(buf, sizeof(buf), "%H:%M:%S", ev->time)] = '\0';
46+
#if RV32_HAS(LOG_COLOR)
47+
fprintf(ev->udata, "%s %s%-5s\x1b[0m \x1b[90m%s:%d:\x1b[0m ", buf,
48+
level_colors[ev->level], level_strings[ev->level], ev->file,
49+
ev->line);
50+
#else
51+
fprintf(ev->udata, "%s %-5s %s:%d: ", buf, level_strings[ev->level],
52+
ev->file, ev->line);
53+
#endif /* RV32_HAS(LOG_COLOR) */
54+
vfprintf(ev->udata, ev->fmt, ev->ap);
55+
fprintf(ev->udata, "\n");
56+
fflush(ev->udata);
57+
}
58+
59+
static void lock(void)
60+
{
61+
if (L.lock)
62+
L.lock(true, L.udata);
63+
}
64+
65+
static void unlock(void)
66+
{
67+
if (L.lock)
68+
L.lock(false, L.udata);
69+
}
70+
71+
const char *log_level_string(int level)
72+
{
73+
return level_strings[level];
74+
}
75+
76+
void log_set_lock(log_lock_func_t fn, void *udata)
77+
{
78+
L.lock = fn;
79+
L.udata = udata;
80+
}
81+
82+
void log_set_level(int level)
83+
{
84+
L.level = level;
85+
}
86+
87+
void log_set_quiet(bool enable)
88+
{
89+
L.quiet = enable;
90+
}
91+
92+
static void init_event(log_event_t *ev, void *udata)
93+
{
94+
if (!ev->time) {
95+
time_t t = time(NULL);
96+
ev->time = localtime(&t);
97+
}
98+
ev->udata = udata;
99+
}
100+
101+
void log_set_stdout_stream(FILE *stream)
102+
{
103+
L.udata = stream;
104+
}
105+
106+
void log_impl(int level, const char *file, int line, const char *fmt, ...)
107+
{
108+
log_event_t ev = {
109+
.fmt = fmt,
110+
.file = file,
111+
.line = line,
112+
.level = level,
113+
};
114+
115+
lock();
116+
117+
if (!L.quiet && level >= L.level) {
118+
init_event(&ev, L.udata ? L.udata : stdout);
119+
va_start(ev.ap, fmt);
120+
stdout_callback(&ev);
121+
va_end(ev.ap);
122+
}
123+
124+
unlock();
125+
}

0 commit comments

Comments
 (0)