首页 > 解决方案 > 在 Caliper 基准测试期间绑定实例

问题描述

我最近的任务是对我们 API 的一些特性进行基准测试,我一直在使用 Caliper 来做这件事。它看起来相当简单,实际上非常强大,我一直在关注这里的教程:

如何使用卡尺

来自创作者的教程

我在我们当前的应用程序中使用 Guice,所以当我尝试运行基准测试时,我确保注入我需要的服务

下面提供的是我的代码。我尝试使用自己的@injected注释设置变量,我尝试直接启动它们(尽管有太多的依赖关系需要处理,我也必须启动它们)。@Parms注释不起作用,因为我需要一个字符串类型来迭代(参数只接受字符串,有文档说明如果它是另一种类型该怎么办,但它需要一个.toString类型方法)

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;
    }
}

当我们尝试运行它时

mvn exec:java -Dexec.mainClass="com.google.caliper.runner.CaliperMain" -Dexec.args="com.~~~.~~~.api.benchmark.CampaignBenchmark"

我们得到以下

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.

问题是:我应该在什么时候进行注射,我该怎么做?我应该有一个包装类设置吗?

快速更新

我忘了提到它是 DropWizard (0.7.1) 应用程序的一部分。我们使用资源并将其注入环境

前任:

environment.jersey().register(injector.getInstance(CampaignManagementResource.class));

这些资源包含运行它们所需的服务,它们作为@Inject 包含在内,尽管我们从未在其他任何地方实际指定绑定。

@Inject
private CampaignMetadataService apiCampaignMetadataService;

我应该为 DropWizard 调整什么,或者我应该只是模拟服务?

标签: javaguicecaliper

解决方案


将 Guice 视为一个 Hashtable。使用 Guice 包含以下部分:

  • 创建哈希表
  • 把东西放进去
  • 从中得到东西

您的代码创建哈希表并对其进行查询,但从不将任何内容放入其中:

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);
}

Guice 哈希表在Module类中填充。毫无疑问,你有一个CampaignModuleAdvertisingModule躺在某个地方。它可能看起来像这样:

public class CampaignModule extends AbstractModule {
  @Override protected void configure() {
    bind(CampaignMetadataService.class).to(CampaignMetadataServiceImplementation.class);
}

这样做是将一个<CampaignMetadataService, CampaignMetadataServiceImplementation>条目放入 Guice 哈希表中。展望未来,任何请求 的实例的人CampaignMetadataService都会收到 的实例CampaignMetadataServiceImplementation

所以在你的代码中,你需要让 Guice 知道这个模块:

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);
}

你做的其他一切都很好。旁注:@Inject构造函数和字段上的注释不会做任何事情,因为您从不要求 Guice 为您提供CampaignBenchmark. 这些只能删除。


推荐阅读