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

Update build scripts to always run tests for all MXNet engine types #71

Open
wants to merge 6 commits into
base: v0.x.x
Choose a base branch
from

Conversation

joseph-wakeling-sociomantic
Copy link
Contributor

This patch updates Build.mak to ensure that unittests and integration tests will always be run for all of the supported engine types. As well as making it easier to run tests for all engines locally, this will make it possible to greatly simplify our CI setup.

This patch updates `Build.mak` to ensure that unittests and integration
tests will always be run for all of the supported engine types.  As well
as making it easier to run tests for all engines locally, this will make
it possible to greatly simplify our CI setup.
@joseph-wakeling-sociomantic
Copy link
Contributor Author

joseph-wakeling-sociomantic commented Jun 21, 2018

I'm going to follow up with a separate travis config patch. For now I want to see the behavioural difference without it ;-)

Since `Build.mak` now takes care of running tests with all engines, we
can greatly simplify the number and configuration of Travis CI jobs.
This patch reduces the setup to cover development and production builds
for D1 and D2 respectively.
Build.mak Outdated
$O/test-mxnet.stamp: $O/test-mxnet download-mnist
$(call run_test,$<,NaiveEngine)
$(call run_test,$<,ThreadedEngine)
$(call run_test,$<,ThreadedEnginePerDevice)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

It occurs to me that an even better option would be to have a variable defining the supported engines (set in Config.mak if not already defined) and just foreach over the entries in that variable. But I'm finding it tricky to work out how best to do that :-\

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Specifically: how to implement an appropriate for loop. Although I guess a simple, manual way is to have a separate run_test_with_all_engines function which takes a single parameter (the test to run).

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've tried with:

run_test_with_all_engines = $(foreach engine,$(SUPPORTED_MXNET_ENGINES),$(call run_test,$1,$(engine)))

... but for some reason, this only ever picks up on the first entry in the SUPPORTED_MXNET_ENGINES variable.

Choose a reason for hiding this comment

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

BTW, the dependency of $O/test-mxnet is added automatically by Makd, you don't need to put it explicitly.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is what I assumed, but it didn't work without it. :-\

@joseph-wakeling-sociomantic
Copy link
Contributor Author

I've pushed a follow-up patch to simplify the Travis config.

Copy link

Choose a reason for hiding this comment

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

LGTM, although I suggest to still provide the option to run one individual test, in case only one fails, so you don't have to repeat all of them.

@leandro-lucarella-sociomantic

(I would also squash)

@joseph-wakeling-sociomantic
Copy link
Contributor Author

LGTM, although I suggest to still provide the option to run one individual test, in case only one fails, so you don't have to repeat all of them.

Agreed -- it's what I was trying to do by defining a variable defining the engines to test. Do you have any suggestions for how to do the kind of foreach loop I had in mind above?

@joseph-wakeling-sociomantic
Copy link
Contributor Author

I've pushed a squash! patch that I think gets things working w.r.t. allowing the engines to be specified via an environment variable. @mihails-strasuns-sociomantic @leandro-lucarella-sociomantic what do you think? I suspect it's probably possible to simplify.

@joseph-wakeling-sociomantic
Copy link
Contributor Author

... and one more minor tweak.

Build.mak Outdated
# extra runtime dependencies for integration tests
$O/test-mxnet.stamp: override ITFLAGS += $(MNIST_DATA_DIR)
$O/test-mxnet.stamp: download-mnist
$Vtouch $@ # override default implementation
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This tweak (and the similar one for unittests) is necessary to avoid the "normal" integration test run from also taking place. Would be nice to avoid if possible though.

Copy link
Contributor

Choose a reason for hiding this comment

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

Another approach is to have the MXNet default engine always executed and then change TEST_MXNET_ENGINES to mean additional engines to test.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes. It would probably be best in that case to remove the MXNET_ENGINE_TYPE ?= line from Config.mak as then we test the default case where the engine is not specified in the environment.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That would also avoid the need to override the default environment with lines like

$O/allunittests.stamp:
    $Vtouch $@

... so it's probably better this way.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

HOWEVER, note that this then messes up things from another point of view, which is: what if I want to specify just one engine to test with, not as an extra?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Obviously I can do MXNET_ENGINE_TYPE=MyEngine TEST_MXNET_ENGINES= make test all but this is getting finnicky. That's why from a CI perspective I'd rather have just one variable (the build script's variable) be the one the user has to care about.

Build.mak Outdated
# extra build dependencies for integration tests
$O/test-mxnet: override LDFLAGS += -lz
$O/test-mxnet: override DFLAGS += -debug=MXNetHandleManualFree

# run integration tests with all specified engines
$(eval $(call test_with_engines,$O/test-mxnet,$(TEST_MXNET_ENGINES)))
Copy link
Contributor Author

Choose a reason for hiding this comment

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

It'd be nice to be able to simplify these lines.

Build.mak Outdated
endef

# helper function to generate targets for per-engine test runs
test_with_engines = $(foreach engine,$2,\
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Probably here we can drop $2 and just use $(TEST_MXNET_ENGINES) directly.

Build.mak Outdated
# extra build dependencies for integration tests
$O/test-mxnet: override LDFLAGS += -lz
$O/test-mxnet: override DFLAGS += -debug=MXNetHandleManualFree

# run integration tests with all specified engines
$(eval $(call test_with_engines,$O/test-mxnet))
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is there any way to avoid the $(eval $(call ... here? They both seem to be necessary, otherwise I get a missing separator error.

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think so. call is needed to run the function and eval is needed to evaluate the returned string describing the target (https://www.gnu.org/software/make/manual/html_node/Eval-Function.html#Eval-Function).

@@ -1,5 +1,7 @@
INTEGRATIONTEST := integrationtest

TEST_MXNET_ENGINES ?= NaiveEngine ThreadedEngine ThreadedEnginePerDevice
Copy link
Contributor Author

Choose a reason for hiding this comment

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

One small note here: it should not be possible that the TEST_MXNET_ENGINES variable be empty. If I do:

TEST_MXNET_ENGINES= make test all

... then obviously, nothing runs. But there should be a failure in this case (which doesn't happen right now). Any thoughts on the best way to implement this?

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't see why there should be a failure. Because with empty TEST_MXNET_ENGINES you define no additional targets.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jens-mueller-sociomantic right now they are not ADDITIONAL targets. Of course, we could make it so. It just means that NaiveEngine tests will run twice. But if we kill the MXNET_ENGINE_TYPE ?= line in Config.mak, maybe that has sense (as we then test the case where MXNET_ENGINE_TYPE is not specified in the environment).

Choose a reason for hiding this comment

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

Perhaps define the TEST_MXNET_ENGINES variable to some "always fails" phony target by default, requiring that user override it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@nemanja-boric-sociomantic I'm not sure it really fixes the issue, because the problem is precisely if the user overrides the variable to set it to empty (a phony target won't solve that).

Choose a reason for hiding this comment

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

Right, I was talking nonsense. Hm...

Choose a reason for hiding this comment

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

There's a way of defining default to be NativeEngine and filtering it out from the TEST_MXNET_ENGINES.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

TBH I think this is overthinking things. If someone sets the field to empty that's their problem ...

Build.mak Outdated

# helper function to generate targets for per-engine test runs
test_with_engines = $(foreach engine,$(TEST_MXNET_ENGINES),\
$(eval $(call run_test_with_engine,$1,$(engine))))
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Both eval and call seem necessary here too to avoid a missing separator error.

Build.mak Outdated
$(1).stamp: $(1)-$(2).stamp

$(1)-$(2).stamp: $1
$(call exec,MXNET_ENGINE_TYPE=$2 $1,$1,$2)
Copy link
Contributor

Choose a reason for hiding this comment

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

Don't you miss a $Vtouch $(1)-$(2).stamp here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, most likely. I think I tried using $@ and there was some objection to that (which I assume is about ordering of make's expansion of these tokens).

Build.mak Outdated

$O/%unittests: override LDFLAGS += -lz

# run unittests with all specified engines
$(eval $(call test_with_engines,$O/allunittests))
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Minor note: would it be worth killing the need to write $O here? i.e. have the calls be

$(eval $(call test_with_engines,allunittests)
$(eval $(call test_with_engines,test-mxnet)

... and do the $O stuff under the hood ... ?

… types

This should get the dependencies working OK.
@joseph-wakeling-sociomantic
Copy link
Contributor Author

I've pushed a further fixup patch. @leandro-lucarella-sociomantic @nemanja-boric-sociomantic you may want to review this solution ;-)

$O/test-mxnet.stamp: override ITFLAGS += $(MNIST_DATA_DIR)
$O/test-mxnet.stamp: download-mnist
$(eval $(call run_test_with_dependency,$O/test-mxnet,\
override ITFLAGS += $(MNIST_DATA_DIR)))
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'm not convinced that this is working. The output of make -p gives e.g.:

build/devel/tmp/test-mxnet-NaiveEngine.stamp: ITFLAGS += ~/data/mnist

(where ~ is expanded;-) but the integration tests (and download script) both use the default value of this parameter, despite it being set in my Config.local.mak.

That said, this might be something other than how this Build.mak is written.

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've just validated with current v0.x.x, where things are working w.r.t. running test-mxnet, but not in terms of where the download script places things (which appears to be an existing Build.mak bug). So there seems to be some problem with how this override is being handled.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It looks like it's because the custom rule implemented in test_with_engine is missing the details used in the default makd integration test run:

# General rule to Run the test suite binaries
$O/test-%.stamp: $O/test-%
    $(call exec,$< $(_test_drt_opts) $(ITFLAGS),$<,run)
    $Vtouch $@

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Now, I can easily add $$(_test_drt_opts) $$(ITFLAGS) to the call implemented here in Build.mak, but note that this is supposed to work for unittests as well as integration tests and there are no similar settings in vanilla makd where unittests are concerned.

@leandro-lucarella-sociomantic @nemanja-boric-sociomantic any advice/thoughts?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

_test_drt_opts are common, I think, but unittests versus integration-tests should use UTFLAGS versus ITFLAGS respectively. I guess I could define a function to work out (based on the full target name) which options should be used. But it really feels like this is starting to turn into a nasty code duplication between how this Build.mak is doing things, versus how makd is doing things.

Choose a reason for hiding this comment

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

TBH, my feeling is you have reached the level of the complexity where we should consider supporting this as a makd feature. @leandro-lucarella-sociomantic

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, I agree, this looks like it needs makd support.

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 question is what level of makd support, though. It's not clear to me that it needs to be at the level of actually supporting the feature needed here (i.e. running tests multiple times for different environment settings). It might suffice to provide make functions to run the tests associated with a particular .stamp target (so that create a custom recipe without having to do a complete re-duplication of what makd already does).

@leandro-lucarella-sociomantic any thoughts? (Including "Drop this for now and get on with more actionable items" :-P)

Choose a reason for hiding this comment

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

@leandro-lucarella-sociomantic your input is needed here :-)

download-mnist))

# run integration tests with all specified engines
$(eval $(call run_test_with_engines,$O/test-mxnet))
Copy link
Contributor Author

Choose a reason for hiding this comment

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

A weird behaviour: right now make test always re-runs the integration tests, despite the associated .stamp files being correctly generated. Any idea what could be responsible?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK, it looks like the download-mnist phony target is responsible, since there is no associated .stamp. It's independent of this PR, just more noticeable.


$O/%unittests: override LDFLAGS += -lz

# run unittests with all specified engines
$(eval $(call run_test_with_engines,$O/allunittests))
Copy link
Contributor Author

Choose a reason for hiding this comment

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

OTOH this works just fine, with no re-running of unittests after they have been successfully run once.

@joseph-wakeling-sociomantic
Copy link
Contributor Author

Considering how many successive issues we're uncovering, I'm starting to question whether this PR is worth the complications it introduces.

I wonder whether it might be worth trying to distill the essence of what is wanted here (i.e. ability to replay both unittests and integration tests with multiple different runtime environment settings), and implement support directly in makd, to ensure no conflicts or duplication of effort.

@joseph-wakeling-sociomantic
Copy link
Contributor Author

Removing the milestone and lowering the priority, as I think we should take a bit of a step back from this: so far it's proving more complicated than it's worth for the benefit. Would still be interested in addressing the slightly bigger picture feature properly at some point, though.

@leandro-lucarella-sociomantic

I've pushed a further fixup patch. @leandro-lucarella-sociomantic @nemanja-boric-sociomantic you may want to review this solution ;-)

I saw @nemanja-boric-sociomantic already reviewed this, I will skip it then . If you still need my input pplease mention me again!

@joseph-wakeling-sociomantic
Copy link
Contributor Author

@leandro-lucarella-sociomantic it would be good to have your input on the outcome of our discussions, in particular w.r.t. our discussion point here: #71 (comment)

... but I don't think you need to approach this with any urgency. I can also file an upstream makd issue distilling the requirements (which could be addressed either with a concrete how-to-do-it-downstream solution, or by makd features, or a bit of both, depending on what's required).

@leandro-lucarella-sociomantic

To be honest the discussion is too long and it would take a lot of time to go through it, so if it is an option to write a more generic and summarized issue in makd, that would be the best option IMHO (if appropriate, i.e. if there is anything wrong with it or a new feature is needed).

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

Successfully merging this pull request may close these issues.

4 participants