private Future<?> executeTestJob(DependencyGraphExecutorFactory<?> factory) { final InMemoryLKVMarketDataProvider marketDataProvider = new InMemoryLKVMarketDataProvider(); final MarketDataProviderResolver marketDataProviderResolver = new SingleMarketDataProviderResolver( new SingletonMarketDataProviderFactory(marketDataProvider)); final InMemoryFunctionRepository functionRepository = new InMemoryFunctionRepository(); _functionCount.set(0); final MockFunction mockFunction = new MockFunction(new ComputationTarget("Foo")) { @Override public Set<ComputedValue> execute( FunctionExecutionContext executionContext, FunctionInputs inputs, ComputationTarget target, Set<ValueRequirement> desiredValues) { try { Thread.sleep(JOB_FINISH_TIME / (JOB_SIZE * 2)); } catch (InterruptedException e) { throw new OpenGammaRuntimeException("Function interrupted", e); } _functionCount.incrementAndGet(); return super.execute(executionContext, inputs, target, desiredValues); } }; functionRepository.addFunction(mockFunction); final FunctionCompilationContext compilationContext = new FunctionCompilationContext(); final CompiledFunctionService compilationService = new CompiledFunctionService( functionRepository, new CachingFunctionRepositoryCompiler(), compilationContext); compilationService.initialize(); final FunctionResolver functionResolver = new DefaultFunctionResolver(compilationService); final MockSecuritySource securitySource = new MockSecuritySource(); final MockPositionSource positionSource = new MockPositionSource(); final ViewComputationCacheSource computationCacheSource = new InMemoryViewComputationCacheSource(FudgeContext.GLOBAL_DEFAULT); final FunctionInvocationStatisticsGatherer functionInvocationStatistics = new DiscardingInvocationStatisticsGatherer(); final ViewProcessorQueryReceiver viewProcessorQueryReceiver = new ViewProcessorQueryReceiver(); final ViewProcessorQuerySender viewProcessorQuerySender = new ViewProcessorQuerySender(InMemoryRequestConduit.create(viewProcessorQueryReceiver)); final FunctionExecutionContext executionContext = new FunctionExecutionContext(); final ComputationTargetResolver targetResolver = new DefaultComputationTargetResolver(securitySource, positionSource); final JobDispatcher jobDispatcher = new JobDispatcher( new LocalNodeJobInvoker( new LocalCalculationNode( computationCacheSource, compilationService, executionContext, targetResolver, viewProcessorQuerySender, Executors.newCachedThreadPool(), functionInvocationStatistics))); final ViewPermissionProvider viewPermissionProvider = new DefaultViewPermissionProvider(); final GraphExecutorStatisticsGathererProvider graphExecutorStatisticsProvider = new DiscardingGraphStatisticsGathererProvider(); ViewDefinition viewDefinition = new ViewDefinition("TestView", UserPrincipal.getTestUser()); viewDefinition.addViewCalculationConfiguration( new ViewCalculationConfiguration(viewDefinition, "default")); MockViewDefinitionRepository viewDefinitionRepository = new MockViewDefinitionRepository(); viewDefinitionRepository.addDefinition(viewDefinition); final ViewProcessContext vpc = new ViewProcessContext( viewDefinitionRepository, viewPermissionProvider, marketDataProviderResolver, compilationService, functionResolver, positionSource, securitySource, new DefaultCachingComputationTargetResolver( new DefaultComputationTargetResolver(securitySource, positionSource), EHCacheUtils.createCacheManager()), computationCacheSource, jobDispatcher, viewProcessorQueryReceiver, factory, graphExecutorStatisticsProvider); final DependencyGraph graph = new DependencyGraph("Default"); DependencyNode previous = null; for (int i = 0; i < JOB_SIZE; i++) { DependencyNode node = new DependencyNode(new ComputationTarget("Foo")); node.setFunction(mockFunction); if (previous != null) { node.addInputNode(previous); } graph.addDependencyNode(node); previous = node; } final Map<String, DependencyGraph> graphs = new HashMap<String, DependencyGraph>(); graphs.put(graph.getCalculationConfigurationName(), graph); CompiledViewDefinitionWithGraphsImpl viewEvaluationModel = new CompiledViewDefinitionWithGraphsImpl( viewDefinition, graphs, new SimplePortfolio("Test Portfolio"), 0); ViewCycleExecutionOptions cycleOptions = new ViewCycleExecutionOptions(); cycleOptions.setValuationTime(Instant.ofEpochMillis(1)); cycleOptions.setMarketDataSpecification(new MarketDataSpecification()); final SingleComputationCycle cycle = new SingleComputationCycle( UniqueId.of("Test", "Cycle1"), UniqueId.of("Test", "ViewProcess1"), vpc, viewEvaluationModel, cycleOptions, VersionCorrection.of(Instant.ofEpochMillis(1), Instant.ofEpochMillis(1))); return cycle.getDependencyGraphExecutor().execute(graph, cycle.getStatisticsGatherer()); }
@Test public void testCycleSimpleGraph() { ViewProcessorTestEnvironment env = new ViewProcessorTestEnvironment(); env.init(); CompiledViewDefinitionWithGraphsImpl compiledViewDefinition = env.compileViewDefinition(Instant.now(), VersionCorrection.LATEST); DependencyGraph graph = compiledViewDefinition.getDependencyGraph( ViewProcessorTestEnvironment.TEST_CALC_CONFIG_NAME); DependencyGraph cycledGraph = cycleObject(DependencyGraph.class, graph); assertEquals( graph.getCalculationConfigurationName(), cycledGraph.getCalculationConfigurationName()); assertEquals(graph.getAllComputationTargets(), cycledGraph.getAllComputationTargets()); assertEquals(graph.getOutputSpecifications(), cycledGraph.getOutputSpecifications()); assertEquals(graph.getSize(), cycledGraph.getSize()); assertEquals( graph.getTerminalOutputSpecifications(), cycledGraph.getTerminalOutputSpecifications()); for (DependencyNode node : graph.getDependencyNodes()) { boolean isRoot = graph.getRootNodes().contains(node); for (ValueSpecification spec : node.getOutputValues()) { DependencyNode equivalentNode = cycledGraph.getNodeProducing(spec); assertEquals(isRoot, cycledGraph.getRootNodes().contains(equivalentNode)); assertEquals(node.getInputValues(), equivalentNode.getInputValues()); assertEquals(node.getOutputValues(), equivalentNode.getOutputValues()); assertEquals(node.getTerminalOutputValues(), equivalentNode.getTerminalOutputValues()); } } }
/** * Determines whether to run, and runs if required, a single computation cycle using the following * rules: * * <ul> * <li>A computation cycle can only be triggered if the relevant minimum computation period has * passed since the start of the previous cycle. * <li>A computation cycle will be forced if the relevant maximum computation period has passed * since the start of the previous cycle. * <li>A full computation is preferred over a delta computation if both are possible. * <li>Performing a full computation also updates the times to the next delta computation; i.e. * a full computation is considered to be as good as a delta. * </ul> */ @Override protected void runOneCycle() { // Exception handling is important here to ensure that computation jobs do not just die quietly // while consumers are // potentially blocked, waiting for results. ViewCycleType cycleType; try { cycleType = waitForNextCycle(); } catch (InterruptedException e) { return; } ViewCycleExecutionOptions executionOptions = null; try { if (!getExecutionOptions().getExecutionSequence().isEmpty()) { executionOptions = getExecutionOptions() .getExecutionSequence() .getNext(getExecutionOptions().getDefaultExecutionOptions()); s_logger.debug("Next cycle execution options: {}", executionOptions); } if (executionOptions == null) { s_logger.info("No more view cycle execution options"); processCompleted(); return; } } catch (Exception e) { s_logger.error( "Error obtaining next view cycle execution options from sequence for view process " + getViewProcess(), e); return; } if (executionOptions.getMarketDataSpecification() == null) { s_logger.error("No market data specification for cycle"); cycleExecutionFailed( executionOptions, new OpenGammaRuntimeException("No market data specification for cycle")); return; } MarketDataSnapshot marketDataSnapshot; try { if (getMarketDataProvider() == null || !getMarketDataProvider().isCompatible(executionOptions.getMarketDataSpecification())) { // A different market data provider is required. We support this because we can, but // changing provider is not the // most efficient operation. if (getMarketDataProvider() != null) { s_logger.info("Replacing market data provider between cycles"); } replaceMarketDataProvider(executionOptions.getMarketDataSpecification()); } // Obtain the snapshot in case it is needed, but don't explicitly initialise it until the data // is required marketDataSnapshot = getMarketDataProvider().snapshot(executionOptions.getMarketDataSpecification()); } catch (Exception e) { s_logger.error("Error with market data provider", e); cycleExecutionFailed( executionOptions, new OpenGammaRuntimeException("Error with market data provider", e)); return; } Instant compilationValuationTime; try { if (executionOptions.getValuationTime() != null) { compilationValuationTime = executionOptions.getValuationTime(); } else { // Neither the cycle-specific options nor the defaults have overridden the valuation time so // use the time // associated with the market data snapshot. To avoid initialising the snapshot perhaps // before the required // inputs are known or even subscribed to, only ask for an indication at the moment. compilationValuationTime = marketDataSnapshot.getSnapshotTimeIndication(); if (compilationValuationTime == null) { throw new OpenGammaRuntimeException( "Market data snapshot " + marketDataSnapshot + " produced a null indication of snapshot time"); } } } catch (Exception e) { s_logger.error("Error obtaining compilation valuation time", e); cycleExecutionFailed( executionOptions, new OpenGammaRuntimeException("Error obtaining compilation valuation time", e)); return; } VersionCorrection versionCorrection = getResolvedVersionCorrection(); final CompiledViewDefinitionWithGraphsImpl compiledViewDefinition; try { compiledViewDefinition = getCompiledViewDefinition(compilationValuationTime, versionCorrection); if (isTerminated()) { return; // [PLAT-1904] } } catch (Exception e) { String message = MessageFormat.format( "Error obtaining compiled view definition {0} for time {1} at version-correction {2}", getViewProcess().getDefinitionId(), compilationValuationTime, versionCorrection); s_logger.error(message); cycleExecutionFailed(executionOptions, new OpenGammaRuntimeException(message, e)); return; } try { if (getExecutionOptions().getFlags().contains(ViewExecutionFlags.AWAIT_MARKET_DATA)) { marketDataSnapshot.init( compiledViewDefinition.getMarketDataRequirements().keySet(), MARKET_DATA_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); } else { marketDataSnapshot.init(); } if (executionOptions.getValuationTime() == null) { executionOptions.setValuationTime(marketDataSnapshot.getSnapshotTime()); } } catch (Exception e) { s_logger.error("Error initializing snapshot {}", marketDataSnapshot); cycleExecutionFailed( executionOptions, new OpenGammaRuntimeException("Error initializing snapshot" + marketDataSnapshot, e)); } EngineResourceReference<SingleComputationCycle> cycleReference; try { cycleReference = createCycle(executionOptions, compiledViewDefinition, versionCorrection); } catch (Exception e) { s_logger.error("Error creating next view cycle for view process " + getViewProcess(), e); return; } if (_executeCycles) { try { final SingleComputationCycle singleComputationCycle = cycleReference.get(); final Set<String> configurationNames = singleComputationCycle.getAllCalculationConfigurationNames(); final HashMap<String, Collection<ComputationTarget>> configToComputationTargets = new HashMap<String, Collection<ComputationTarget>>(); for (String configName : configurationNames) { DependencyGraph dependencyGraph = singleComputationCycle.getExecutableDependencyGraph(configName); configToComputationTargets.put(configName, dependencyGraph.getAllComputationTargets()); } final HashMap<String, Map<ValueSpecification, Set<ValueRequirement>>> configToTerminalOutputs = new HashMap<String, Map<ValueSpecification, Set<ValueRequirement>>>(); for (String configName : configurationNames) { DependencyGraph dependencyGraph = singleComputationCycle.getExecutableDependencyGraph(configName); configToTerminalOutputs.put(configName, dependencyGraph.getTerminalOutputs()); } cycleInitiated( new SimpleCycleInfo( marketDataSnapshot.getUniqueId(), compiledViewDefinition.getViewDefinition().getUniqueId(), versionCorrection, executionOptions.getValuationTime(), configurationNames, configToComputationTargets, configToTerminalOutputs)); executeViewCycle( cycleType, cycleReference, marketDataSnapshot, getViewProcess().getCalcJobResultExecutorService()); } catch (InterruptedException e) { // Execution interrupted - don't propagate as failure s_logger.info("View cycle execution interrupted for view process {}", getViewProcess()); cycleReference.release(); return; } catch (Exception e) { // Execution failed s_logger.error("View cycle execution failed for view process " + getViewProcess(), e); cycleReference.release(); cycleExecutionFailed(executionOptions, e); return; } } // Don't push the results through if we've been terminated, since another computation job could // be running already // and the fact that we've been terminated means the view is no longer interested in the result. // Just die quietly. if (isTerminated()) { cycleReference.release(); return; } if (_executeCycles) { cycleCompleted(cycleReference.get()); } if (getExecutionOptions().getExecutionSequence().isEmpty()) { processCompleted(); } if (_executeCycles) { if (_previousCycleReference != null) { _previousCycleReference.release(); } _previousCycleReference = cycleReference; } }