how should one instrument their modules?
That's the need for documentation :-) The basic idea is to instrument complete applications, similar to coverage reports. Usually this would be the current application. Simply put into a setup
function with instrument_app(:my_concurrent_app)
, then run the tests.
@x4lldux
about nice visualisation of parallel runs.
I am not sure about the current reporting facilities. How about using a numeric index before each command, something like A.001
, A.002
, ... B.001
, B.002
, so that we can relate these calls to each other. For better reading convince we should increate the indentation after that index such that line breaks for command parameters are easily identified as belonging to a certain indexed command.
Simply put into a setup function with instrument_app(:my_concurrent_app), then run the tests.
then with the :gen_server
vs GenServer
argument, whether GenServer
simply uses or fully reimplements the functionality, doesn't matter, because I don't see any recursion in instrumentation, so even if GenServer would use :gen_server
under the surface, instrumenter wouldn't do a thing (unless someone would instument_app(:elixir)
;)
:gen_server
and GenServer
so I think instumenter needs to recognize both,
:gen_server
andGenServer
Yes, either that or instrumenting calls to :gen
and instrument :elixir
as well as stdllib
. That sounds silly. I would go for instrumenting calls to Elixir's standard functionalities such as GenServer
, GenEvent
, Task
and so on.
How about using a numeric index before each command, something like A.001 , A.002, ... B.001, B.002,
printer already supports this with cmd_args: false
option. but what I was thinking, was instead of pretty boxes like I showed earlier, something like this:
Sequential commands:
var1 = DSL.cache(4, "")
# -> true
Process 1 (5, 5):
#! var2 = DSL.cache(1, "𐀀")
# -> true
#! var3 = DSL.cache(10, "")
# -> true
#! var4 = DSL.cache(0, "")
# -> true
#! var5 = DSL.cache(-1, "Ϊŕ")
# -> :error
#! var6 = DSL.cache(-1, "𐀄݅醧")
# -> true
Process 2 (6, 6):
#! var7 = DSL.flush()
# -> true
#! var8 = DSL.cache(6, "")
# -> true
#! var9 = DSL.cache(2, "")
# -> true
#! var10 = DSL.cache(3, "ҡ")
# -> true
#! var11 = DSL.cache(9, "")
# -> true
#! var12 = DSL.find(8)
# -> {:error, :not_found}
Yes, either that or instrumenting calls to :gen and instrument :elixir as well as stdllib.
That sounds slooooow.
Gen*
family, :gen_*
family and Tasks by default. but also give a quick way to instrument other modules instead of full apps
var8
is always set after var2
because Process 2 could be faster than Process 1.
'd instrument Gen family, :gen_ family and Tasks by default. but also give a quick way to instrument other modules instead of full apps
We need something different: the current application under test needs to instrumented such that calls to Gen*
, Task
, SuperVisor
, :ets
, :dets
and some replaced by their instrumented variants (I would like to add support for send()
and receive..do..end
as well).
instrument_module()
, which is the working horse of instrument_app()
.
So there is indication that e.g. var8 is always set after var2 because Process 2 could be faster than Process 1.
this isn't clearly present even in this version:
Sequential step:
var1 = DSL.cache(10, 1)
var2 = DSL.cache(8, -2)
Parallel step:
+------------P0-------------+ +-----------P1-----------+
| var3 = DSL.cache(-18, -2) | | var5 = DSL.cache(8, 3) |
| var4 = DSL.find(-2) | | var6 = DSL.cache(0, 0) |
+---------------------------+ | var7 = DSL.flush() |
+------------------------+
Marking a dependency runtime: false will not start it as part of the application supervision tree when your main application is started.
mix propcheck.list_counter_examples
What do you think?