Again guys if you find a good alternative to the library calls in the code just tell me. Asm is a good option but not yet. I want to know what's best to have it done.. in C. Thanks again all.
|
Quote:
I'm not sure whether you are suggesting redesign to avoid needing a three way branch or you are suggesting that two if statements would be faster for a three way branch (it usually isn't). I haven't looked carefully enough to be certain but contrast Code:
switch (*p) { Code:
switch (dotsCount) { In the second case the programmer may know things about the likely or possible values that would allow a double if statement to be faster than a switch, and the whole three way branch might not be as fundamental to the problem. So I'm not sure, but maybe something faster than the switch could be coded. A switch is often less efficient than if statements because the compiler is usually forced to generate a "default" path even if you don't make one explicit and even if the problem doesn't require it. But in these examples the problem does require a default path and it is explicit in the source code. |
Quote:
Quote:
|
Quote:
Quote:
By the way I made some comparisons with my original code and a version of the code where I made modifications that includes 'p[-1]' and 'token = p + 1'. The gcc compiler (verson 4.1.2) generates the same output from both codes when optimization flag is enabled. But when the outputs are not optimized, the modified version appeared to be faster. Both still have the same number of instructions and both also use increment statements (INCL and INC) but there was a difference in size and the targets. The compiler understood my original code as something that implies direct modification to the memory (like INCL) and not something that uses the registers first. With this form, it's probably slower right? It was probably quicker if the compiler did not recognize p + 1 as "INC AX". You guys are right. Maybe I really shouldn't over-underestimate compilers. P[-1] by the way also appears to yield faster code. ntubski and johnsfine was right all along. I'll change my code with those and have it finalized. Thanks for the help guys. I'll take a note of all the things you posted here. And by the way I still can't understand some of johnsfine's statements. I know the concept of caches but what are cache misses and what's a partial tail merge? :) Maybe I'll study those when I have time and after I finish the project. The first working prototype of its first and maybe final protocol (at last after many attempts to make it complete and perfect according to its requirement) is soon to be finished. ;) |
Quote:
Quote:
1) Flow of control. If the last action before a point where flow of control joins is identical on both sides, the compiler can reduce code size and maybe cache misses by joining earlier than the source code indicates. This is most common and most obvious in the join after if/then/else. Compare: Code:
if (a) { foo(x,y,z); } else { p=something; foo(p,y,z); } Code:
p=x; if (!a) { p=something; } foo(p,y,z); In the first case, the last operation before joining is calling foo() so the compiler could join it early, but the benefits are tiny and an optimizer would be unlikely to guess joining early was right. Since parameters are normally set up right to left, there is a more obvious early join in Code:
if (a) { foo(x,y,z); } else { p=something; foo(x,y,p); } Now consider Code:
p=x; if (a) {foo(p,y,z);} else { p=something; foo(p,y,z);} 2) The other meaning of "tail merge" is when the last operation of a function (before returning) is to call a function with a compatible parameter stack and the same return value (turns out to be very common in advanced C++ programming). The compiler can change the code to jump to the other function instead of calling it, and thus save the extra layer of return. |
Got it. I now know what you mean. It seems that there are parts of the code that only compilers can optimize.
By the way, regarding my second switch statement, do you think it's better if I just do something like: Code:
} else if (dotsCount && dotsCount != 1) { Code:
} else if (dotsCount) { |
I don't feel like studying your source code enough to decide the optimal way to branch on dotsCount. But I doubt that either of the above would be better than just using a switch.
What's wrong with Code:
} else if (dotsCount >= 2) { |
Thanks for figuring that out. I was always focusing on something like 'n |/&/^ m' so i forgot simple things like > or >=.
|
If we're still in the micro-optimization game, then I would suggest optimizing for the common case: directories which are not "." or "..". This way for most of the time the code doesn't have to look out for dots, just slash and end of string. EDIT: And by putting a '/' at the end of workBuffer a lot of checks for end of string can be removed. By the way, I uncovered a bug when I tried this out:
Code:
workBufferSize += cwdLength + 1; // +1 is needed for the '/' between cwd and sourceArg Code:
// ensure that workBuffer ends in "/", to reduce checks for '\0' |
Thanks for the fix. That was a bug indeed. I'll take a look at the new code as well. Later.
|
Quote:
Your performance bottleneck is not "C", it's your shell script. |
Quote:
Some folks say that I'm wasting so much time to this code but actually I only created the code in an hour or two and posted it. I also took time making replies to this thread and analyzing the code but it was fun anyway. I spent most of the time on my scripts and not on this program. Now regarding my shell script, I think it is already in its most optimized form but I know that I can never be sure with it so I also plan to post it later but the script is part of a project and I still can't find a proper license for it. There's nothing much in the project but I just want to be careful. Regardless, thanks for your reminders. |
Quote:
And why is the script a shell one in the first place ? |
Quote:
|
Quote:
|
All times are GMT -5. The time now is 10:25 AM. |