|
|
Test and Benchmark results of Real-time File System(RTFS) on Renesas M16 board |
Members
|
|
|
Gayathri TK [gtambar@ncsu.edu] Jayush Luniya [jrluniya@ncsu.edu]
|
Portability issues |
|
|
Once we implemented the file system on a normal Linux machine, we worked on porting our code to Renesas M16C board. The board comes with SDK which has a very primitive C compiler. The following were some of the issues we faced while we were porting our file system to Renesas M16C architecture:
- We had to statically allocate all the memory needed for our file system as malloc() was failing
- Function activation frame size is only 255 bytes. Hence cannot allocate more than 255 bytes for local variables inside any function.
- There was absolutely no memory protection. We found our data structures were getting corrupted because of collision between the call stack and global data area
- Need to explicitly cast pointers as FAR pointers while assigning a pointer in global area to local variable or when passing them as function arguments
|
Testing the file system |
|
|
In order to test our file system on the architecture, we decided to simulate the shell environment on the M16C processor using input and output buffers. The input command buffer contains all commands, like mkdir, touch, read etc. that need to be executed. The test code reads the commands one by one and calls the corresponding shell routine which internally calls the file system api to execute the command. for eg. shell command mkdir calls the file system api f_mkdir to actually create the directory in the file system. For append command, which requires contents of the file to be retrieved from stdin, we implemented rtfs_getc() method to return characters from buffer instead of standard input stream.
The output is written to a buffer by calling rtfs_printf() instead of normal printf(). After each command is executed, the contents of the buffer can be viewed by using KD30, a debugging tool available with Renesas board SDK.
|
Providing Real Time Guarantees to RTFS |
|
|
In order to provide real time guarantees to our file system, we had to put a bound on the following parameters:
Preprocessor Directive |
Description |
Value |
MAX_DIR_ENTRIES |
Maximum number of directories in the file system |
32 |
MAX_SUB_DIRS |
Maximum number of subdirectories inside a directory |
5 |
MAX_DIR_DEPTH |
Maximum depth of a directory in the hierarchy |
5 |
MAX_DIR_NAME_SIZE |
Maximum characters in directory name |
8 |
MAX_FILE_ENTRIES |
Maximum no of files in a directory |
4 |
NUM_BLKS_PER_FILE |
Maximum no of data blocks in a file |
4 |
MAX_FILE_SIZE |
Maximum file size |
( NUM_BLKS_PER_FILE *DATA_BLK_SIZE) |
MAX_FILE_NAME_SIZE |
Maximum characters in file name |
8 |
MAX_FILE_DESC |
Maximum number of file descriptors |
32 |
MAX_DATA_BLKS |
Maximum number of data blocks in the file system |
32 |
DATA_BLK_SIZE |
Data block size |
128 |
|
RTFS Benchmarking |
|
|
Unlike most general-purpose applications, embedded applications often have to meet various stringent constraints, such as time, space, and power. Constraints on time are commonly formulated as worst-case (WC) constraints. If these timing constraints are not met, even only occasionally in a hard real-time system, then the system may not be considered functional. The worst-case execution time (WCET) must be calculated to determine if a timing constraint will always be met. For our file system to be used as a real time file system, we should be able to provide average and worst case scenarios for all of the file system operations.
|
Renesas M16C Timers |
|
|
Renesas SDK does not provide functions like gettimeofday(), which are used to measure the time taken for a certain module in normal applications. Hence we had to use timers provided in architecture to calculate time bounds for file system operations. We had used Timer-mode timer for this purpose. The MCU has 11 timers. The timers are separated into two categories by functionality, 5 Timer A's and 6 Timer B's. All 11 timers can operate in Timer Mode. We had used Timer A0 in timer mode. In Timer Mode, the counter register counts down using the selected clock source until the counter underflows (0000 to FFFFh). At this point, the timer interrupt request bit is set and the contents of the reload register are loaded back into the counter and countdown continues.
We had implemented a timer with 1 millisecond granularity. We used two counters in the timer:
- count - counts the number of seconds since the last reset
- time_cnt - counts the number of milliseconds since the last reset
Since each of the file operations were taking less than 1 millisecond, we measured time taken for a series of similar operations and averaged them out to get the average and worst case execution times.
|
Test cases used for benchmarking |
|
|
For each of the operations, we had to come up with scenarios to accurately calculate the average and worst case access times. The test cases used are listed below:
- mkdir, rmdir
Average Case:Created/deleted 2 directories under root, at level 1, 6 directories in level 2, 5 directories in level 3, 2 directories in level 4 and 5 directories in level 5, which is MAX_DIR_DEPTH
Worst Case:Since we have maintaining the directory hierarchy as shown in the figure below,
the worst case access time would be access the last subdirectory at level = MAX_DIR_DEPTH. If MAX_DIR_DEPTH = 2 and MAX_SUB_DIRS=2, then in Fig 1, access creating/removing subdir2 would give the worst case access time.
- creat, close, open, remove
Average Case:Created 4 files under directories in level 1, 4 files under directories in level 2, 4 files in level 3, 1 file in level 4 and 6 files under directories in level 5 (MAX_DIR_DEPTH)
Worst Case:Accessing any file in a directory which is at level = MAX_DIR_DEPTH and is at the end of the subdirectory chain will lead to worst case access time for that file.
- write, read
Average Case:Wrote/read one data block of data into/from each of the files created above
Worst Case:There should not be any significant difference between worst and average case access time for read and write operations as they access files using file descriptors, which is basically a pointer to the File control block (FCB). This can clearly be observed from the experimental results. We measured the time taken to write to all blocks allocated to a file and read all data blocks of a file created in a directory at the highest depth.
|
Benchmark Results |
|
|
The following table shows our experimental results.
Operation |
Average Case Access Times |
Worst-case Access Times |
|
# Access |
Total Time taken (in millisecs) |
Time per Access |
# Access |
Total Time taken (in millisecs) |
Time per Access |
mkdir |
20 |
7 |
0.35 |
20 |
12 |
0.6 |
rmdir |
20 |
7 |
0.35 |
20 |
12 |
0.6 |
creat |
20 |
11 |
0.55 |
8 |
6 |
0.75 |
open |
20 |
10 |
0.5 |
8 |
6 |
0.75 |
remove |
20 |
13 |
0.65 |
8 |
7 |
0.875 |
read |
25 |
13 |
0.52 |
20 |
12 |
0.6 |
write |
25 |
13 |
0.52 |
20 |
11 |
0.55 |
|
Future Work |
|
|
- Reducing Average and Worst case bounds
While we were interested in building a very simplistic file system, we did not have a chance to look or evaluate our code to see if we could optimize our file system to improve average or worst case access time. One possible future work could be to optimize our file system code to improve the real time bounds provided above.
- Porting the file system to Flash Memory - Persistent file system
As we had mentioned before, RTFS is a RAM-based, which makes it a temporary. Data can be stored only until power is available. If data must be available across power failures, there is a need to build a persistent file system, such as a flash file system. Flash file systems have their own limitations, which were discussed in detail in our prior report. Renesas M16C board comes with 384K flash memory, and hence porting RTFS to flash memory would be a very interesting future work of this project.
|
|