Skip to content

Conversation

@ccoffing
Copy link
Contributor

@ccoffing ccoffing commented Jan 6, 2024

This is a grab-bag of little optimizations that have accumulated. It's only a few bytes and few cycles saved here and there, but I'm tired of sitting on them, and combined they cut 4k off the 2.8M media.

I think most of these changes stand on their own merits. But a few like to ls were specifically sought out to bring the binary down to the next smaller filesystem block size.

@ghaerr
Copy link
Owner

ghaerr commented Jan 6, 2024

Hello @ccoffing,

Nice work 4K byte savings on the distribution!! :)

I am guessing that some of the literal string splits were designed for use with string merging at link time? Also, pretty tricky work on using a bit vector for testing for the C0 control codes. Fast, though initially hard to understand until I got it. Thanks for leaving in the switch statement as documentation.

I found one line that might be in error, along with a couple other small comments posted separately for your comment.

Thank you!

/* Cursor to left edge */
strcpy(seq, "\r");
abAppend(&ab,seq,strlen(seq));
abAppend(&ab,"\r",2);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be abAppend(...,1)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

printf(" ");
printtrig(&tabs[i].list[j].trigger);
printf("%s", tabs[i].list[j].command);
fputs(tabs[i].list[j].command, stdout);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure that replacing printf with fputs is actually smaller here? In the case where printf is already used, it seems this just drags in another function, rather than saving space as it would if printf could actually be replaced in full at link time. Same for a few other cases with printf->fputs substitution in this commit.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, changing back to printf saves 16 bytes on the binary. Done.

seteuid(getuid());
do {
fprintf(stderr, "Do you want to retry the same edit? ");
fputs("Do you want to retry the same edit? ", stderr);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here as commented above.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Turns out that this doesn't matter (function and binary are same size either way) since something else is already pulling fputs in. In general, fputs should take fewer cycles when no formatting is required. But since I don't know how/why fputs is getting pulled in already (maybe it can be trimmed out...) I'll revert this for now.

if (r == LINES - 1)
printf("\r");
else printf("\n");
putc(r == LINES - 1 ? '\r' : '\n', stdout);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to printf->fputs described above, doesn't this just drag in fputc, while also including printf? I would guess this results in large .o and final codefile ? (Same issue in tty-cp437.c).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think my initial motivation here was to save a few CPU cycles by avoiding the unnecessary format string parsing in vfprintf (which, when multiplied across screen redraws, might actually matter).

I just did a test:

Reverting cons.c and tty-cp437.c to printf as before, and doing a clean build:

$ du -b target/bin/
1337353	target/bin/

Clean build with cons.c and tty-cp437.c putc change as first presented here. Slightly trading space for time:

$ du -b target/bin/
1337369	target/bin/

Then converting cons.c and tty-cp437.c to fputs/putc (no printf), and doing a clean build:

$ du -b target/bin/
1337321	target/bin/

So it seems that avoiding printf where possible in tty code is a [tiny] win, whether the goal is to optimize for space or time.

Also unnecessary to clear errno when it is guaranteed to be set
- More precisely trim out DEBUG code
- Combine similar strings
- Use libc string functions not custom.  Some would be omitted ifdef
  SYS5, but we don't define that for other reasons; just rely on __STDC__.
- Reduce size of linenoise
Where possible, prefer setbuf over setvbuf (64 bytes smaller) or skip
explicitly setting to fully buffered when it isn't necessary.

It's redundant to fflush stdout,stderr before exit because stdio already
registers its own atexit to fflush stdout and stderr.
@ghaerr
Copy link
Owner

ghaerr commented Jan 7, 2024

After looking a bit more closely at cons.c and tty-cp437.c, I agree with your original finding that printf should be replaced by fputs, mainly because fputs is already used in both (as is printf/sprintf) so primarily a speed gain without pulling in another function. Also, fputs.c calls putc so using that costs nothing once fputs is used.

However - some executables are linked with $(TINYPRINTF) (elkscmd/lib/tiny_printf.c). In those cases, beware of the substitutions used above because tiny_printf.c only defines a smaller/fast vprintf but no fputs or fputc, so with those programs its more tricky to decrease their size. This could all be fixed by changing a few things in tiny_printf.c but care needs to be taken as it was written only for programs that call printf/sprintf but don't do anything else with stdio.

Thank you!

@ghaerr ghaerr merged commit bf32a25 into ghaerr:master Jan 7, 2024
@ccoffing
Copy link
Contributor Author

ccoffing commented Jan 7, 2024

However - some executables are linked with $(TINYPRINTF) (elkscmd/lib/tiny_printf.c). In those cases, beware of the substitutions used above because tiny_printf.c only defines a smaller/fast vprintf but no fputs or fputc, so with those programs

So regarding TINYPRINTF, it's possible with my changes that some binaries went up in size and some went down (but on average a win). I'll keep that in mind. Thanks!

@ccoffing ccoffing deleted the size-reductions branch January 7, 2024 04:18
@ghaerr
Copy link
Owner

ghaerr commented Jan 7, 2024

regarding TINYPRINTF, it's possible with my changes that some binaries went up in size and some went down

Technically possible, but I don't think any of the programs you changed link with TINYPRINTF. In general, only very small programs that would otherwise use write / errmsg etc but can't because they need sprintf or a printf format designator have been linked with TINYPRINTF. It was invented just for that purpose, see elkscmd/rm.c for a good example.

TINYPRINTF is definitely not compatible with anything that calls fopen, and no file I/O other than stdin/stdout.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants