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

Adding heatmap and graph_type #134

Merged
merged 25 commits into from
Jun 12, 2018
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 22 additions & 14 deletions apps/xprof_gui/priv/src/actions/CollectingActions.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { isEqual, isEmpty } from 'lodash';
import * as types from '../constants/ActionTypes';
import * as XProf from '../api';
import { getMfas, getData, getCalls } from '../selectors';
import { getAllMonitored, getData, getCalls } from '../selectors';
import { setCallsControl, getCalleesForFunctions } from './';
import { determineNextData, determineNextCalls } from '../utils';

export const updateListMonitoringFunctions = mfas => ({
export const updateListMonitoringFunctions = monitoredCollection => ({
type: types.UPDATE_MONITORED_FUNCTIONS,
mfas,
monitoredCollection,
});

const updateData = data => ({
Expand All @@ -22,18 +22,21 @@ const updateCalls = calls => ({

export const getMonitoredFunctions = () => async (dispatch, getState) => {
const state = getState();
const mfas = getMfas(state);
const monitoredCollection = getAllMonitored(state);

const { json, error } = await XProf.getAllMonitoredFunctions();

if (error) {
console.log('ERROR: ', error);
} else if (!isEqual(mfas, json)) {
const newMfas = json.filter(mfa => !mfas.map(f => f[3]).includes(mfa[3]));
const newControls = newMfas.reduce(
(control, mfa) => ({
} else if (!isEqual(monitoredCollection, json)) {
const queries = monitoredCollection.map(monitored => monitored.query);
const newMonitoredCollection = json
.filter(monitored => !queries
.includes(monitored.query));
const newControls = newMonitoredCollection.reduce(
(control, monitored) => ({
...control,
[mfa[3]]: {
[monitored.query]: {
threshold: undefined,
limit: undefined,
collecting: false,
Expand All @@ -42,17 +45,17 @@ export const getMonitoredFunctions = () => async (dispatch, getState) => {
{},
);

dispatch(getCalleesForFunctions(newMfas));
dispatch(getCalleesForFunctions(newMonitoredCollection));
dispatch(setCallsControl(newControls));
dispatch(updateListMonitoringFunctions(json));
}
};

export const getFunctionsData = () => async (dispatch, getState) => {
const state = getState();
const mfas = getMfas(state);
const monitoredCollection = getAllMonitored(state);
const data = getData(state);
const nextData = await determineNextData(mfas, data);
const nextData = await determineNextData(monitoredCollection, data);

if (!isEmpty(nextData)) {
dispatch(updateData({ ...data, ...nextData }));
Expand All @@ -61,9 +64,14 @@ export const getFunctionsData = () => async (dispatch, getState) => {

export const getFunctionsCalls = () => async (dispatch, getState) => {
const state = getState();
const mfas = getMfas(state);
const monitoredCollection = getAllMonitored(state);
const calls = getCalls(state);
const nextCalls = await determineNextCalls(dispatch, state, mfas, calls);
const nextCalls = await determineNextCalls(
dispatch,
state,
monitoredCollection,
calls,
);

if (!isEmpty(nextCalls)) {
dispatch(updateCalls({ ...calls, ...nextCalls }));
Expand Down
23 changes: 12 additions & 11 deletions apps/xprof_gui/priv/src/actions/ExploringActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,30 +22,31 @@ export const calleeClick = callee => (dispatch) => {
dispatch(startMonitoringFunction(callee));
};

export const getCallees = mfa => async (dispatch) => {
const name = mfa[3];
export const getCallees = monitored => async (dispatch) => {
const name = monitored.query;

const { json, error } = await XProf.getFunctionsCallees(
mfa[0],
mfa[1],
mfa[2],
monitored.mfa[0],
monitored.mfa[1],
monitored.mfa[2],
);

if (error) console.log('ERROR');
else if (json.length) dispatch(addCallees({ [name]: json }));
else console.log('NO CALLES FOUND!');
};

export const getCalleesForFunctions = mfas => async (dispatch) => {
export const getCalleesForFunctions = monitoredCollection => async (dispatch,
) => {
const callees = {};

await Promise.all(mfas.map(async (mfa) => {
const fun = mfa[3];
await Promise.all(monitoredCollection.map(async (monitored) => {
const fun = monitored.query;

const { json, error } = await XProf.getFunctionsCallees(
mfa[0],
mfa[1],
mfa[2],
monitored.mfa[0],
monitored.mfa[1],
monitored.mfa[2],
);

if (error) console.log('ERROR');
Expand Down
34 changes: 21 additions & 13 deletions apps/xprof_gui/priv/src/actions/MonitoringActions.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,35 @@
import { getMfas } from '../selectors';
import { getAllMonitored } from '../selectors';
import * as types from '../constants/ActionTypes';
import * as XProf from '../api';

const stopMonitoringFunctionRequest = mfas => ({
const stopMonitoringFunctionRequest = monitoredCollection => ({
type: types.STOP_MONITORING_FUNCTION,
mfas,
monitoredCollection,
});

const stopMonitoringFunctionError = mfas => ({
const stopMonitoringFunctionError = monitoredCollection => ({
type: types.STOP_MONITORING_FUNCTION_ERROR,
mfas,
monitoredCollection,
});

export const stopMonitoringFunction = mfa => async (dispatch, getState) => {
export const stopMonitoringFunction = monitored => async (
dispatch, getState,
) => {
const state = getState();
const mfas = getMfas(state);
const mfasReduced = mfas.filter(m => m[3] !== mfa[3]);
const monitoredCollection = getAllMonitored(state);
const monitoredCollectionReduced = monitoredCollection
.filter(f => f.query !== monitored.query);

dispatch(stopMonitoringFunctionRequest(mfasReduced));
dispatch(stopMonitoringFunctionRequest(monitoredCollectionReduced));

const { error } = await XProf.stopMonitoringFunction(mfa[0], mfa[1], mfa[2]);
const { error } = await XProf.stopMonitoringFunction(
monitored.mfa[0],
monitored.mfa[1],
monitored.mfa[2],
);
if (error) {
console.log('ERROR: ', error);
dispatch(stopMonitoringFunctionError(mfas));
dispatch(stopMonitoringFunctionError(monitoredCollection));
}
};

Expand All @@ -31,8 +38,9 @@ export const startMonitoringFunction = functionName => async (
getState,
) => {
const state = getState();
const mfas = getMfas(state);
const isMonitored = mfas.filter(mfa => mfa[3] === functionName).length;
const monitoredCollection = getAllMonitored(state);
const isMonitored = monitoredCollection
.filter(monitored => monitored.query === functionName).length;

if (!isMonitored) {
const { error } = await XProf.startMonitoringFunction(functionName);
Expand Down
39 changes: 20 additions & 19 deletions apps/xprof_gui/priv/src/actions/TracingActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ const updateLastCallsForFunction = (functionName, sortedCalls) => ({
sortedCalls,
});

export const toggleExpandItem = (mfa, item) => (dispatch, getState) => {
export const toggleExpandItem = (monitored, item) => (dispatch, getState) => {
const state = getState();
const functionName = mfa[3];
const functionName = monitored.query;
const lastCallsForFunction = getLastCallsForFunction(state, functionName);

const updatedItems = lastCallsForFunction.sort.items.map((call) => {
Expand All @@ -38,29 +38,30 @@ export const toggleExpandItem = (mfa, item) => (dispatch, getState) => {
dispatch(toggleExpand(functionName, updatedItems));
};

export const toggleCallsTracing = mfa => async (dispatch, getState) => {
export const toggleCallsTracing = monitored => async (dispatch, getState) => {
const state = getState();
const functionName = mfa[3];
const functionName = monitored.query;
const control = getFunctionControl(state, functionName);
const nextControl = await determineNextControlSwitch(control, mfa);
const nextControl = await determineNextControlSwitch(control, monitored);
dispatch(setCallsControl({ [functionName]: nextControl }));
};

export const handleThresholdChange = (mfa, value) => (dispatch, getState) => {
const state = getState();
const functionName = mfa[3];
const { limit, collecting } = getFunctionControl(state, functionName);
const nextControl = {
threshold: value,
limit,
collecting,
export const handleThresholdChange = (monitored, value) =>
(dispatch, getState) => {
const state = getState();
const functionName = monitored.query;
const { limit, collecting } = getFunctionControl(state, functionName);
const nextControl = {
threshold: value,
limit,
collecting,
};
dispatch(setCallsControl({ [functionName]: nextControl }));
};
dispatch(setCallsControl({ [functionName]: nextControl }));
};

export const handleLimitChange = (mfa, value) => (dispatch, getState) => {
export const handleLimitChange = (monitored, value) => (dispatch, getState) => {
const state = getState();
const functionName = mfa[3];
const functionName = monitored.query;
const { threshold, collecting } = getFunctionControl(state, functionName);
const nextControl = {
threshold,
Expand All @@ -70,9 +71,9 @@ export const handleLimitChange = (mfa, value) => (dispatch, getState) => {
dispatch(setCallsControl({ [functionName]: nextControl }));
};

export const sortCallsBy = (mfa, column) => (dispatch, getState) => {
export const sortCallsBy = (monitored, column) => (dispatch, getState) => {
const state = getState();
const functionName = mfa[3];
const functionName = monitored.query;
const lastCallsForFunction = getLastCallsForFunction(state, functionName);
const order =
lastCallsForFunction.sort.column === column &&
Expand Down
18 changes: 11 additions & 7 deletions apps/xprof_gui/priv/src/components/functions/Functions.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ import { FUNCTIONS_INTERVAL } from '../../constants';

const propTypes = {
getMonitoredFunctions: PropTypes.func.isRequired,
mfas: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.any)).isRequired,
monitoredCollection: PropTypes.arrayOf(PropTypes.shape({
graph_type: PropTypes.string,
mfa: PropTypes.arrayOf(PropTypes.any),
query: PropTypes.string,
})).isRequired,
};

class Functions extends React.Component {
Expand All @@ -24,14 +28,14 @@ class Functions extends React.Component {
}

render() {
const { mfas } = this.props;
const { monitoredCollection } = this.props;
return (
<div>
{mfas.map((mfa, index) => (
<div key={mfa[3]}>
<MonitoringContainer mfa={mfa} />
<TracingContainer mfa={mfa} />
{index < mfas.length - 1 ? (
{monitoredCollection.map((monitored, index) => (
<div key={monitored.query}>
<MonitoringContainer monitored={monitored} />
<TracingContainer monitored={monitored} />
{index < monitoredCollection.length - 1 ? (
<hr className="function-separator" />
) : null}
</div>
Expand Down
56 changes: 45 additions & 11 deletions apps/xprof_gui/priv/src/components/monitoring/Graph/Graph.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,55 @@ import React from 'react';
import C3Chart from 'react-c3js';
import 'c3/c3.css';
import { AXIS, DATA, GRID, POINT, TRANSITION } from '../../../constants';
import Grid from './Grid/Grid';

const composeID = q => `${q.replace(/[^A-Za-z0-9_-]/g, '-')}`;

const propTypes = {
dps: PropTypes.arrayOf(PropTypes.object).isRequired,
type: PropTypes.string.isRequired,
query: PropTypes.string.isRequired,
Copy link
Collaborator

@gomoripeti gomoripeti May 9, 2018

Choose a reason for hiding this comment

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

Maybe this can be the whole m json object (including mfa and query fields) to address above issue with composing the ID
(we need to find a good name for the json object, I dont know if function is good enough, in generic sense this is a monitor or monitored-object, which can be an m:f/a but also can be garbage_collection or memory in the future)

Copy link
Contributor Author

@jlampar jlampar May 10, 2018

Choose a reason for hiding this comment

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

If we are composing the ID inside GraphPanel, in the end we are only passing the ID to the Graph and the panel has access to the whole m object. The panel needs the object as it decomposes it into the grid props, whereas the grid just receives stuff from the panel.
In case of renaming the JSON object I think this is a good idea, as for now the object named mfa has also a mfa property which is a little bit confusing (that's why I renamed it somewhere to m in loops or arguments).
I propose we:

  • rename the mfas to monitoredCollection,
  • rename the mfa to monitored.

What do you think?

Copy link
Collaborator

Choose a reason for hiding this comment

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

right, so query is only there so that the Graph can show it as a title. +1 for renamings

passId: PropTypes.number.isRequired,
};

const Graph = ({
dps,
type,
query,
passId,
}) => {
const queryID = composeID(query);
const wrapperID = `graphWrapper-${queryID}`;
const wrapper = document.getElementById(wrapperID);
if (type === 'grid') {
Copy link
Contributor

Choose a reason for hiding this comment

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

We can create constant for types and put it somewhere in src/constants

export const GRAPH_TYPES = {
  GRID: 'grid',
  LINE: 'line',
}

return (
<div
id={wrapperID}
style={{
textAlign: 'center',
justifyContent: 'center',
}}
>
{wrapper && <Grid
data={{ ...DATA, json: dps }}
outerWidth={wrapper.clientWidth}
graphID={passId}
/>}
</div>
Copy link
Contributor

Choose a reason for hiding this comment

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

As we introduced new type of graph we can add new layer of components here

  switch (type) {
    case GRAPH_TYPES.GRID:
      return (<GridGraph />);
    case GRAPH_TYPES.LINE:
      return (<LineGraph />);
    default:
      return
  }
     

);
}
return (
<div>
<C3Chart
data={{ ...DATA, json: dps }}
point={POINT}
grid={GRID}
axis={AXIS}
transition={TRANSITION}
/>
</div>
);
};
const Graph = ({ dps }) => (
<div>
<C3Chart
data={{ ...DATA, json: dps }}
point={POINT}
grid={GRID}
axis={AXIS}
transition={TRANSITION}
/>
</div>
);
Graph.propTypes = propTypes;

export default Graph;
Loading