Skip to content
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

Optimizations #123

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open

Optimizations #123

wants to merge 8 commits into from

Conversation

pbfy0
Copy link
Contributor

@pbfy0 pbfy0 commented May 13, 2018

This pull requests contains several optimizations, both for speed and for code size.

  • Moves the actual definitions in keys.h to its own source file. This makes both libndls and ndless_resources.tns significantly (~30kb) smaller, because both of them contained several copies of the table before.
  • Default to looking for ndless.cfg in get_documents_dir()/ndless/ndless.cfg.tns, and cache its last seen location in memory if it's not found there. Closes Repeated searching for ndless.cfg is extremely slow if you have a lot of documents #120.
  • After locating programs for file associations, store their full paths back in ndless.cfg.tns. If the program is moved from the stored path, ndless will find the new location and store it. If the program is deleted, ndless will revert the config entry back to a basename only.

As a result, ndless will write the location it has found the associated program to ndless.cfg.
This significantly speeds opening programs with association, since it avoids trawling through the entire filesystem each time.
}

static char cfg_path[FILENAME_MAX] = {0};
Copy link
Contributor

Choose a reason for hiding this comment

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

Move into the function itself

@@ -102,10 +102,23 @@ BOOL isKeyPressed(const t_key *key);
void wait_key_pressed(void);
void wait_no_key_pressed(void);
/* config.c */
struct cfg_entry {
char key[15];
// short val_offset;
Copy link
Contributor

Choose a reason for hiding this comment

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

?

@@ -102,10 +102,23 @@ BOOL isKeyPressed(const t_key *key);
void wait_key_pressed(void);
void wait_no_key_pressed(void);
/* config.c */
struct cfg_entry {
char key[15];
Copy link
Contributor

Choose a reason for hiding this comment

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

Fixed size?

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 thought this was OK because the only place that wrote to the cfg in code (cfg_register_fileext) also limited the key size to 15. However, this doesn't take into account manual editing of the config file

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, for the fileext it might apply, but not for other keys. Part of this effort of refactoring this is to make the code more versatile, isn't it? :-)

Choose a reason for hiding this comment

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

How would one make this a non-static size? A variable and a helper function?

Copy link
Contributor

Choose a reason for hiding this comment

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

Most likely, yes. Alternatively make the fixed size bigger and provide it as a global constant.

}

void cfg_open(void) {
char path[300];
char path[FILENAME_MAX];
Copy link
Contributor

Choose a reason for hiding this comment

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

PATH_MAX?

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 saw FILENAME_MAX used in this way in a few other places in ndless (i.e. in ld_exec_with_args). Doesn't make it right, but that was my logic.

if (!strcmp(key, kv_offsets[i][0] + file_content))
return kv_offsets[i][1] + file_content;
struct cfg_entry *e = &cfg_entries[i];
//printf("%s, %s\n", key, e->key);
Copy link
Contributor

Choose a reason for hiding this comment

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

Debug statement, remove.

return kv_offsets[i][1] + file_content;
struct cfg_entry *e = &cfg_entries[i];
//printf("%s, %s\n", key, e->key);
if (!strcmp(key, e->key)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Remove unnecessary {}, use == 0.


void cfg_put(const char *key, const char *val) {
struct cfg_entry *entr;
if((entr = cfg_get_entry(key))) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Move the assignment outside of the if.

return e == NULL ? NULL : e->value;
}

static int strict_strcmp(const char *a, const char *b) {
Copy link
Contributor

Choose a reason for hiding this comment

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

What does this do?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Normal strcmp returns zero if the second string starts with the first string. This version doesn't.

Copy link
Contributor

Choose a reason for hiding this comment

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

It doesn't. strcmp("foo", "foobar") = -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.

You're right. I tested with gcc.godbolt.org and misread mvn as mov.

return memcmp(a, b, (l1 < l2 ? l1 : l2)+1);
}

void cfg_put_entry(struct cfg_entry *entr, const char *val) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This API doesn't make sense - struct cfg_entry already has a value.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The point of this is to let config.c only write out the config if a change has actually happened. Maybe it would be better to make struct cfg_entry opaque outside of config.c. cfg_put_entry isn't a great name, I guess. Maybe cfg_set_value?

Copy link
Contributor

@Vogtinator Vogtinator May 13, 2018

Choose a reason for hiding this comment

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

Yes, cfg_entry should be opaque.

@Vogtinator
Copy link
Contributor

Moves the actual definitions in keys.h to its own source file. This makes both libndls and ndless_resources.tns significantly (~30kb) smaller, because both of them contained several copies of the table before.

I wonder why the compiler/linker did not optimize it. It's just a bunch of unused variables. Did you look for it with objdump?

Default to looking for ndless.cfg in get_documents_dir()/ndless/ndless.cfg.tns, and cache its last seen location in memory if it's not found there. Closes #120.

Looks good to me.

After locating programs for file associations, store their full paths back in ndless.cfg.tns. If the program is moved from the stored path, ndless will find the new location and store it. If the program is deleted, ndless will revert the config entry back to a basename only.

I don't like this too much TBH. It adds more complexity to the code for no good reason. Just use the full path in the cfg? ndless should only ever read the config, not change it.

@pbfy0
Copy link
Contributor Author

pbfy0 commented May 13, 2018

For keys.h, I did look at the objdump; I did see seven copies of KEY_NSPIRE_xxx in one of my projects.
The config changes are pretty complicated. Maybe it would be better to have a separate file, managed by ndless, to map program names to file locations?

@pbfy0
Copy link
Contributor Author

pbfy0 commented May 13, 2018

On the other hand, having a better API to manage config entries might be a good thing. cfg_register_fileext currently does nothing if the config entry already exists; this is a little unsatisfactory.

@Vogtinator
Copy link
Contributor

For keys.h, I did look at the objdump; I did see seven copies of KEY_NSPIRE_xxx in one of my projects.
The config changes are pretty complicated. Maybe it would be better to have a separate file, managed by ndless, to map program names to file locations?

I'd say that the cfg file should just contain absolute paths when possible.

On the other hand, having a better API to manage config entries might be a good thing. cfg_register_fileext currently does nothing if the config entry already exists; this is a little unsatisfactory.

I agree.

It should be done in separate steps though, with support for absolute paths in a separate commit from the cfg_ API refactoring. Maybe even split it into separate PRs so that it can be merged independently.

@Vogtinator
Copy link
Contributor

Vogtinator commented May 13, 2018

For keys.h, I did look at the objdump; I did see seven copies of KEY_NSPIRE_xxx in one of my projects.

Seven copies should not be more than a handful of bytes, or were all available key_t listed?

@pbfy0
Copy link
Contributor Author

pbfy0 commented May 13, 2018

All available keys. As I said, it was ~30kb. Not huge, but not negligible either

@Vogtinator
Copy link
Contributor

All available keys. As I said, it was ~30kb. Not huge, but not negligible either

Can you give a (code) example of how it was used? I suspect a huge array of pointers, but then the bug is in that application IMO.

@pbfy0
Copy link
Contributor Author

pbfy0 commented May 14, 2018

Turns out that one is me being stupid; it was a result of compiling with -O0. With any other level of optimization, gcc removes the unused copies.

@adriweb
Copy link
Contributor

adriweb commented Aug 12, 2018

@pbfy0 any update?

@adriweb
Copy link
Contributor

adriweb commented Jun 14, 2020

We're sad to learn that @pbfy0 passed away in December 2019 (see link in his profile)...

Not sure how to help handling this PR, especially as it hadn't been updated since mid-2018. Does someone want to work-on/rebase his commits and add more to take care of @Vogtinator's comments? And of course, keeping authorship for the original commits would be nice and not a problem git-wise.

@gameblabla
Copy link

gameblabla commented Nov 2, 2020

I made my own attempt here, although i wasn't able to keep the authorship of the original commits : (
https://github.com/gameblabla/Ndless/commits/opts

I need to test it though.

EDIT: Ok so it compiles after i made a few changes but still not sure if it works. Should i open a separate pull request ?

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.

Repeated searching for ndless.cfg is extremely slow if you have a lot of documents
5 participants