When you have a performance problem, profiling an application will help you figure out where the bottleneck is. However, most profiling tool have a tendency to slow down the execution by a significant factor and EiffelStudio is unfortunately no different. Nevertheless, we have added a neat class called PROFILING_SETTING that will enable you to enable/disable the profiler on only some parts of an execution.
To make sure you are using this class properly you should know the following:
- Profiling should be enabled in the project settings
- First executed instruction should be a call to
{PROFILING_SETTING}.stop_profiling - Last executed instruction should be a call to
{PROFILING_SETTING}.start_profiling - When profiling a section of code the calls
start_profilingandstop_profiling, they should appear in the same routine, as otherwise the profiler will be confused
With EiffelStudio 6.0, there is also a very handy feature that comes for free with the new project settings structure with libraries. By default libraries do not inherit the `profiling' setting and are therefore excluded from the profiling (thus speeding up the profiling). It simply means that you won't know how much time is spent in a routine from a library, but the time is still accounted for the callers of that routine. If you want to profile a library, you simply need to mark it so in your project configuration.
I've showed that you can profile a certain portion of code, but you can also disable profiling a certain portion too. We use it when profiling the compiler for not tracking the time spent in the parser. Here is an example:
local
l_prof_setting: PROFILING_SETTING
l_is_profiling: BOOLEAN
retried: BOOLEAN
do
if not retried then
create l_prof_setting.make
l_is_profiling := l_prof_setting.is_profiling
l_prof_setting.stop_profiling
-- Your code here
...
end
if l_is_profiling then
check l_prof_setting_not_void: l_prof_setting /= Void end
l_prof_setting.start_profiling
end
rescue
retried := True
retry
end
Ok, it looks a little bit more complicated than what you expected. If you do not care about correctness then you know that you can remove:
- the rescue clause if you do not anticipate exceptions
- the `l_is_profiling' local variable if nothing else is enabling/disabling the profiler
Enjoy Eiffel and profiling!



It would look a lot less complicated if Eiffel had try..finally!
local
l_prof_setting: PROFILING_SETTING
l_is_profiling: BOOLEAN
do
create l_prof_setting.make
try -- WARNING! THIS IS NOT EIFFEL!
l_is_profiling := l_prof_setting.is_profiling
l_prof_setting.stop_profiling
-- Your code here
...
finally -- WARNING! THIS IS NOT EIFFEL!
if l_is_profiling then
l_prof_setting.start_profiling
end
end
end
I've already heard this...
It would be interesting to have an idea of whom in the Eiffel community favor the existing solution over the more traditional try-catch-finally. Note that you can get the required behavior through inline agents when it is a matter of scoping a few instructions with a rescue clause (agreed it looks a little bit heavy).
No try/catch/finally for me
I don't care for any of this try (totally redundant noise word)/catch (rescue seems a better word to me)/finally. I didn't think Peter's example looked any more readable - less if anything. Colin Adams
Two Things...
You should add a shared class
SHARED_PROFILING_SETTINGSproviding single instance access to the settings.Second, it would be nice to have a single routine that starts/stops the profiler, which a client can pass an agent to. The agent is always executed when the profiler polling is suspended.
The agent solution would
The agent solution would definitely simplify the code by hiding the rescue clause from the user. I've added something similar for MEMORY in 6.1, the name of the new routine is called `execute_without_collection'. In PROFILING_SETTINGS, we could have `execute_without_profiling'.
Definitely add the agent
The
SHARED_PROFILE_SETTINGSidea is good. It would make it clear that this is a singleton setting. The current approach of creating a new object, which you then instruct to start and stop, is a bit weird. It feels like you are starting and stopping something local, but you have to imagine that the implementation is starting and stopping some global flag.The agent is a great idea. I've used a similar pattern to ensure, for example, that an EiffelVision application's hourglass cursor gets reset to the the normal mouse cursor even if there's an exception. I've noticed that Eiffel programmers tend to be lax at this, compared with good programmers in languages with
try..finallyat their disposal; partly because Eiffel'srescuemechanism is more heavy-handed in these situations; and partly because the Eiffel philosophy that exceptions are bugs tends to cause us to pretend that they will never happen. (I learned long ago that bugs often occur when you least expect them. That's what attracted me to DbC in the first place. It also made me paranoid about ensuring that resources are always disposed or reset, even in the event of an exception.)Yet another example of the power of Eiffel idioms! I can't understand Colin's opinion that the
try..finallycode looks as complicated as Manu'srescuecode, but Paul has shown a third way. I'm more than happy with this idiom. I just wonder sometimes, however, whether the need to relearn stuff like this just raises too much of a learning barrier for those zillions of programmers out there who, like me, are comfortable with thetry..finallyidiom. Maybe someone will invent an even simpler way someday, that hides therescueand the agent behind some syntactic sugar: maybe something like C#'susing?