blob: de463d45ccdedd25a0fa77c0f6cd8890aa867748 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @author Yuri Kashnikov
*/
/*
The idea of advanced Top-N-Value (with steady and clear parts, and clear interval)
from <"Value profilling and optimization", B.Calder, P.Feller, Journal of Instruction-Level Parallelism, 1999>
*/
#ifndef _VALUE_PROFILE_COLLECTOR_H_
#define _VALUE_PROFILE_COLLECTOR_H_
#include "DrlProfileCollectionFramework.h"
#include "port_mutex.h"
#include "open/vm_util.h"
#include <map>
#define TNV_DEFAULT_CLEAR_VALUE 0
class ValueMethodProfile;
class VPInstructionProfileData;
struct Simple_TNV_Table
{
POINTER_SIZE_INT value;
U_32 frequency;
};
enum ProfileUpdateStrategy {
// Lock when modifying the TNV table, even trivial counter increments.
// This mode is only one that guarantees accurate profiling.
UPDATE_LOCKED,
// Lock when restructuring the TNV table (inserting). Trivial counter
// increments might not be locked (in current implementation they are not
// locked for FirstN table management only)
UPDATE_LOCKED_INSERT,
// When a new value is added to TNV all simultaneous updates to the table
// are skipped
UPDATE_FLAGGED_ALL,
// Only simultaneous inserts to table are skipped, counter updates are
// processed unsafely
UPDATE_FLAGGED_INSERT,
// Completely insafe updates of the TNV table (use with care)
UPDATE_UNSAFE
};
class TNVTableManager {
public:
typedef struct Simple_TNV_Table TableT;
typedef POINTER_SIZE_INT ValueT;
typedef VPInstructionProfileData VPData;
TNVTableManager(U_32 steady_size, U_32 clear_size,
U_32 clear_interval, ProfileUpdateStrategy update_strategy) :
steadySize(steady_size),
clearSize(clear_size),
clearInterval(clear_interval),
updateStrategy(update_strategy)
{}
VPInstructionProfileData* createProfileData();
// finds a given value in TNV table, returns the index, (-1) if not found
I_32 find(TableT* where, ValueT value_to_search, U_32 size);
// clearSize elements are cleared from the top
void clearTopElements(TableT* where);
// returns the index of the minimum element
I_32 findMinIdx(TableT* where, U_32 size);
// returns the maximum value in a given steady TNV table
ValueT findMax(TableT* TNV_where);
// adds value to method profile with appropriate locking of the methProfile
virtual void addNewValue(ValueMethodProfile* methProfile,
VPData* instProfile, ValueT curr_value) = 0;
// flush num_times_profiled data back to the TNV table
// note: unsynchronized method - must be called from synchronized ones
void flushLastValueCounter(VPData* instProfile);
void dumpValues(VPInstructionProfileData* data, std::ostream& os);
protected:
virtual void insert(TableT* where, TableT* clear_part,
ValueT value_to_insert, U_32 times_met) = 0;
const U_32 steadySize, clearSize, clearInterval;
const ProfileUpdateStrategy updateStrategy;
};
class TNVTableDividedManager : public TNVTableManager {
public:
// c-tor
TNVTableDividedManager(U_32 steady_size, U_32 clear_size,
U_32 clear_interval, ProfileUpdateStrategy us) :
TNVTableManager(steady_size, clear_size, clear_interval, us)
{}
virtual void addNewValue(ValueMethodProfile* methProfile,
VPData* instProfile, ValueT curr_value);
protected:
virtual void insert(TableT* where, TableT* clear_part,
ValueT value_to_insert, U_32 times_met);
};
class TNVTableFirstNManager : public TNVTableManager {
public:
// c-tor
TNVTableFirstNManager(U_32 steady_size, U_32 clear_size,
U_32 clear_interval, ProfileUpdateStrategy us) :
TNVTableManager(steady_size, clear_size, clear_interval, us)
{}
virtual void addNewValue(ValueMethodProfile* methProfile,
VPData* instProfile, ValueT curr_value);
private:
void insert(TableT* where, TableT* clear_part,
ValueT value_to_insert, U_32 times_met);
};
class ValueProfileCollector : public ProfileCollector {
public:
enum algotypes {
TNV_DIVIDED,
TNV_FIRST_N
};
ValueProfileCollector(EM_PC_Interface* em, const std::string& name, JIT_Handle genJit,
U_32 _TNV_steady_size, U_32 _TNV_clear_size,
U_32 _clear_interval, algotypes _TNV_algo_type,
ProfileUpdateStrategy update_strategy);
virtual TbsEMClient* getTbsEmClient() const {return (NULL);}
virtual ~ValueProfileCollector();
MethodProfile* getMethodProfile(Method_Handle mh) const ;
ValueMethodProfile* createProfile(Method_Handle mh, U_32 numkeys, U_32 keys[]);
TNVTableManager* getTnvMgr() { return tnvTableManager; }
private:
std::string catName;
bool loggingEnabled;
typedef std::map<Method_Handle, ValueMethodProfile*> ValueProfilesMap;
ValueProfilesMap profilesByMethod;
mutable osmutex_t profilesLock;
TNVTableManager* tnvTableManager;
ProfileUpdateStrategy updateStrategy;
};
class VPInstructionProfileData
{
public:
struct Simple_TNV_Table* TNV_Table;
struct Simple_TNV_Table * TNV_clear_part;
public:
VPInstructionProfileData() :
last_value(TNV_DEFAULT_CLEAR_VALUE),
num_times_profiled(0),
profile_tick(0)
{}
public:
POINTER_SIZE_INT last_value;
U_32 num_times_profiled;
U_32 profile_tick;
};
typedef std::map<U_32, VPInstructionProfileData*> VPDataMap;
class ValueMethodProfile : public MethodProfile {
public:
ValueMethodProfile(ValueProfileCollector* pc, Method_Handle mh);
~ValueMethodProfile();
void lockProfile() {port_mutex_lock(&lock);}
void unlockProfile() {port_mutex_unlock(&lock);}
void dumpValues(std::ostream& os);
void addNewValue(U_32 instructionKey, POINTER_SIZE_INT valueToAdd);
POINTER_SIZE_INT getResult(U_32 instructionKey);
// UpatingState is used to implement UPDATE_FLAGGED_* strategies.
// (updatingState == 1) when method profile is being updated to skip
// concurrent modifications.
// (updatingState == 0) when profile is open for modifications.
U_8* getUpdatingStatePtr() { return &updatingState; }
private:
ValueProfileCollector* getVPC() const;
friend class ValueProfileCollector;
VPDataMap ValueMap;
// The lock and the atomically modified updatingState flag operate per
// method to allow simultaneous updates for distinct methods.
osmutex_t lock;
U_8 updatingState;
};
POINTER_SIZE_INT value_profiler_get_top_value (Method_Profile_Handle mph, U_32 instructionKey);
void value_profiler_add_value (Method_Profile_Handle mph, U_32 instructionKey, POINTER_SIZE_INT valueToAdd);
Method_Profile_Handle value_profiler_create_profile(PC_Handle pch, Method_Handle mh, U_32 numkeys, U_32 keys[]);
void value_profiler_dump_values(Method_Profile_Handle mph, std::ostream& os);
#endif