Reputation: 186
I've recently been tasked with benchmarking some features of our API, and I've been using Caliper to do so. It seems fairly straightforward and is actually quite powerful, I've been following the tutorials here:
I'm working with Guice in our current app, so when I try to run the benchmark, I make sure to inject the services I need
Provided below is my code. I've tried setting the variables with their own @injected
annotation, I've tried initiating them directly (although there's too many dependencies to deal with, and I'd have to initiate them as well). @Parms
annotation won't work because I need to have a string type to iterate through (the parms only takes strings, there's documentation of what to do if it's another type, but it needs a .toString
type method)
package com.~~~.~~~.api.benchmark;
import com.~~~.ds.mongo.orm.user.User;
import com.~~~.~~~.api.exceptions.auth.AccessDeniedException;
import com.~~~.~~~.api.service.authorization.UserService;
import com.~~~.~~~.api.service.campaign.CampaignMetadataService;
import com.google.caliper.BeforeExperiment;
import com.google.caliper.Benchmark;
import com.google.caliper.Param;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
public class CampaignBenchmark {
// === SERVICE INJECTIONS
@Inject
private CampaignMetadataService campaignMetadataService;
@Inject
private UserService userService;
// =============================================
// === BENCHMARK PARMS
@Param({
"7ca8c319",
"49191829"
})
String userId;
@Param({
"485",
"500"
})
String hashAdvertiserId;
// =============================================
// === TESTING PARMS
private User user;
// =============================================
// === SETUP
@Inject
public CampaignBenchmark(){
Injector injector = Guice.createInjector();
this.userService = injector.getInstance(UserService.class);
this.campaignMetadataService = injector.getInstance(CampaignMetadataService.class);
}
@BeforeExperiment
void setUp(){
this.user = userService.getUserByHashedId(userId);
}
// =============================================
// === BENCHMARKS
@Benchmark
int fetchAllCampaign(int reps) throws AccessDeniedException {
VideoIqUser user = this.user;
String hashAdvertiserId = this.hashAdvertiserId;
int dummy = 0;
for(int i=0 ; i<reps ; i++){
dummy |= campaignMetadataService.fetchAllCampaigns(user, hashAdvertiserId).size();
}
return dummy;
}
}
When we try to run it with
mvn exec:java -Dexec.mainClass="com.google.caliper.runner.CaliperMain" -Dexec.args="com.~~~.~~~.api.benchmark.CampaignBenchmark"
We get the following
WARNING: All illegal access operations will be denied in a future release
Experiment selection:
Benchmark Methods: [fetchAllCampaign]
Instruments: [allocation, runtime]
User parameters: {hashAdvertiserId=[485, 500], userId=[7ca8c319, 49191829]}
Virtual machines: [default]
Selection type: Full cartesian product
This selection yields 16 experiments.
Could not create an instance of the benchmark class following reasons:
1) Explicit bindings are required and com.~~~.~~~.api.service.campaign.CampaignMetadataService is not explicitly bound.
2) Explicit bindings are required and com.~~~.~~~.api.service.authorization.UserService is not explicitly bound.
The question is: at what point should I be doing injections, and how do I go about that? Should I have a wrapper class setup?
Quick Update
I forgot to mention that is part of a DropWizard (0.7.1) application. We use resources and inject them into the environment
Ex:
environment.jersey().register(injector.getInstance(CampaignManagementResource.class));
These resources contain the services needed to run them, and they are included as @Inject, though we never actually specify a binding anywhere else.
@Inject
private CampaignMetadataService apiCampaignMetadataService;
Is there something I should adjust for DropWizard, or should I just mock up the services?
Upvotes: 0
Views: 136
Reputation: 6969
Think of Guice as nothing but a Hashtable. Working with Guice has these parts:
Your code creates the hashtable and queries it, but never puts anything in it:
public CampaignBenchmark() {
// Creating the hashtable
Injector injector = Guice.createInjector();
// Retrieving from the hashtable
this.userService = injector.getInstance(UserService.class);
this.campaignMetadataService = injector.getInstance(CampaignMetadataService.class);
}
The Guice hashtable is populated in Module
classes. Undoubtedly, you have a CampaignModule
or AdvertisingModule
lying around somewhere. It probably looks like this:
public class CampaignModule extends AbstractModule {
@Override protected void configure() {
bind(CampaignMetadataService.class).to(CampaignMetadataServiceImplementation.class);
}
What that does is put a <CampaignMetadataService, CampaignMetadataServiceImplementation>
entry into the Guice hashtable. Going forward, whoever asks for an instance of CampaignMetadataService
receives an instance of CampaignMetadataServiceImplementation
.
So in your code, you need to let Guice know about this module:
public CampaignBenchmark() {
// Creating the hashtable and letting modules populate it
Injector injector = Guice.createInjector(new CampaignModule(), new UserModule());
// Retrieving from the hashtable
this.userService = injector.getInstance(UserService.class);
this.campaignMetadataService = injector.getInstance(CampaignMetadataService.class);
}
Everything else you do is fine. Side note: @Inject
annotations on your constructor and fields don't do anything, since you never ask Guice to supply you with instances of CampaignBenchmark
. These can just be deleted.
Upvotes: 0