-
Notifications
You must be signed in to change notification settings - Fork 126
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Speed up malloc/free routines #140
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid using backticks in git commit messages and comments to ensure compatibility with terminal emulators that may not render the backtick character properly.
Instead, use the pair '
or "
(quotation marks).
malloc()
and free()
in lib/c.c
lib/c.c
Outdated
#define CHUNK_SIZE_SZ_MASK 0xFFFFFFFE | ||
#define CHUNK_GET_SIZE(size) (size & CHUNK_SIZE_SZ_MASK) | ||
#define IS_CHUNK_GET_FREED(size) (size & CHUNK_SIZE_FREED_MASK) | ||
#define CHUNK_SET_FREED(size) (size | CHUNK_SIZE_FREED_MASK) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about rewriting CHUNK_SET_FREED
as following?
#define CHUNK_SET_FREED(size) \
size |= CHUNK_SIZE_FREED_MASK
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I encounter some trouble when modifying the macro.
Then, I use the following code to test a function-like macro:
/* test.c */
#define MACRO(a) a += 10
int main()
{
int x = 10;
printf("%d\n", x);
MACRO(x);
printf("%d\n", x);
return 0;
}
$ out/shecc -o test test.c
Error Unrecognized statement token at source location 16802
#define MACRO(a) a += 10
^ Error occurs here
Abnormal program termination
This implies that shecc cannot parse the macro containing compound operator(s) correctly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current parser lacks of the ability to deal with compound assignment operators. So, you have to change the statements.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because the current parser also lacks of the ability to handle assignment operators. Therefore, I think I will use two functions called chunk_set_freed()
and chunk_clear_freed()
to perform the operations instead of using the original macros.
void chunk_set_freed(chunk_t *chunk)
{
chunk->size |= CHUNK_SIZE_FREED_MASK;
}
void chunk_clear_freed(chunk_t *chunk)
{
chunk->size &= CHUNK_SIZE_SZ_MASK;
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I will use two functions called
chunk_set_freed()
andchunk_clear_freed()
to perform the operations instead of using the original macros.
It looks good to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the current parser also lacks of the ability to handle assignment operator.
@ChAoSUnItY, The compound assignment operators consist of a binary operator and the simple assignment operator. At present, there is no support for compound assignment operators. Can you evaluate the feasibility to consolidate the parser for compound assignment operators?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here are the examples that shecc cannot deal with.
#define MACRO1(variable, val) \
variable = variable + val + 10
#define MACRO2(variable, val) \
variable += val + 10
These macros contain an assignment operator and a compound assignment operator, and shecc cannot parse them correctly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here are the examples that shecc cannot deal with.
Create an issue for tracking.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The compound assignment operators consist of a binary operator and the simple assignment operator. At present, there is no support for compound assignment operators.
The current situation is that read_body_assignment
is failed to realize the macro variable and thus returns false since it's possibly not a local variable nor a global variable, which ultimately results in the parser failed to parse current variable and terminated at the operator.
Can you evaluate the feasibility to consolidate the parser for compound assignment operators?
Currently, it seems rather tricky to implement due to the technical debt of macro parsing design (we're not able to determine which syntax parsing we should use to parse macro parameter). Moreover, if we predict it's a lvalue (which in this case it should be) and we use read_lvalue
function to parse the parameter, the function requires a non-null var_t
, which is impossible because we haven't even parsed macro parameter's actual expression; if we predict it's an expression, we'll lose the target address of the lvalue.
This probably could be resolved after we implement tangle back to shecc since macro expansion would only happens in lexer and parser doesn't have to predict what parsing strategy should be used for the expanded macro parameter.
Improve the ASCII art as following:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Provide some timing measurements for the proposed changes.
This commit improves malloc() and free() in lib/c.c to eliminate an unnecessary member from a structure and reduce execution time. First, the member 'ptr' is removed from 'chunk_t'. Originally, it was used to return the starting address of a usable memory region when calling malloc(). However, consider the following code and illustration. typedef struct chunk { struct chunk *next; struct chunk *prev; int size; } chunk_t; chunk_t *chunk = ... |<--- usable memory --->| +------+------+------+-------- ... ----------+ | next | prev | size | : | +------+------+------+-------- ... ----------+ ^ ^ | | chunk (chunk + 1) the starting address returned by malloc(). After removing 'ptr' from 'chunk_t', the starting address of the usable memory region can be obtained by adding 1 to a pointer to 'chunk_t'. Thus, 'ptr' becomes unnecessary, so this member is removed from the structure and malloc() returns the starting address by the mentioned approach. Second, for the free() function, after removing 'ptr' from 'chunk_t', the least significant bit of the member 'size' is used to record a flag and prevent traversing the entire allocation list. The LSB of 'size' is used to check whether a chunk is freed or not, and it is also used to speed up the free() function. If a chunk is in the freelist, the LSB will be set to 1 to indicate that the chunk is freed. Otherwise, the chunk is still in the allocation list and usable when the LSB is 0, and the memory region can be used by the caller who calls malloc(). Next, when calling free(), the address of a chunk can be obtained by moving a pointer which is the parameter of free() backward by sizeof(chunk_t) bytes directly. <--- usable memory ---> +------+------+------+------- ... -------------+ | next | prev | size | : | +------+------+------+------- ... -------------+ ^ ^ | | chunk ptr |<------------------>| sizeof(chunk_t) bytes Eventually, it is unnecessary to traverse the allocation list. The address of a chunk can be obtained by moving the given pointer backward, and the LSB of 'size' can be used to validate the chunk, which can then be moved to the freelist. Close sysprog21#139
I will continue to improve my commit messages and changes later, but I provide my measurements here first. Here is the information on my CPU.
My measurements use
On the
Then, after introducing the proposed changes, it was reduced to about 6.6 seconds and 18 seconds, respectively.
By the proposed changes, the bootstrap time will be significantly reduced. |
Thank @DrXiao for contributing! |
By the way, because I use Thus, here is the latest result of measurements:
However, the bootstrap time is still significantly reduced. |
This commit improves
malloc()
andfree()
inlib/c.c
to eliminate a useless member from a structure and reduce execution time.Refine the definition of
chunk_t
and improve the two functions using techniques similar to glibc.For example, in glibc, it can obtain the starting address of a chunk by a macro called
mem2chunk()
, and the macro moves the given pointer backward directly to get the address of a chunk. Thus, the proposed changes use a similar approach to speed upfree()
.Close #139