Skip to content

Commit 8b1146d

Browse files
committed
Added function to get timings for layers
1 parent da0a36c commit 8b1146d

File tree

5 files changed

+98
-52
lines changed

5 files changed

+98
-52
lines changed

modules/dnn/include/opencv2/dnn/dnn.hpp

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -483,15 +483,15 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN
483483
* order is the same as in layersIds
484484
*/
485485
CV_WRAP void getLayersShapes(const std::vector<MatShape>& netInputShapes,
486-
std::vector<int>* layersIds,
487-
std::vector<std::vector<MatShape> >* inLayersShapes,
488-
std::vector<std::vector<MatShape> >* outLayersShapes) const;
486+
CV_OUT std::vector<int>& layersIds,
487+
CV_OUT std::vector<std::vector<MatShape> >& inLayersShapes,
488+
CV_OUT std::vector<std::vector<MatShape> >& outLayersShapes) const;
489489

490490
/** @overload */
491491
CV_WRAP void getLayersShapes(const MatShape& netInputShape,
492-
std::vector<int>* layersIds,
493-
std::vector<std::vector<MatShape> >* inLayersShapes,
494-
std::vector<std::vector<MatShape> >* outLayersShapes) const;
492+
CV_OUT std::vector<int>& layersIds,
493+
CV_OUT std::vector<std::vector<MatShape> >& inLayersShapes,
494+
CV_OUT std::vector<std::vector<MatShape> >& outLayersShapes) const;
495495

496496
/** @brief Returns input and output shapes for layer with specified
497497
* id in loaded model; preliminary inferencing isn't necessary.
@@ -504,14 +504,14 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN
504504
*/
505505
CV_WRAP void getLayerShapes(const MatShape& netInputShape,
506506
const int layerId,
507-
std::vector<MatShape>* inLayerShapes,
508-
std::vector<MatShape>* outLayerShapes) const;
507+
CV_OUT std::vector<MatShape>& inLayerShapes,
508+
CV_OUT std::vector<MatShape>& outLayerShapes) const;
509509

510510
/** @overload */
511511
CV_WRAP void getLayerShapes(const std::vector<MatShape>& netInputShapes,
512512
const int layerId,
513-
std::vector<MatShape>* inLayerShapes,
514-
std::vector<MatShape>* outLayerShapes) const;
513+
CV_OUT std::vector<MatShape>& inLayerShapes,
514+
CV_OUT std::vector<MatShape>& outLayerShapes) const;
515515

516516
/** @brief Computes FLOP for whole loaded model with specified input shapes.
517517
* @param netInputShapes vector of shapes for all net inputs.
@@ -566,18 +566,28 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN
566566
* @param blobs output parameter to store resulting bytes for intermediate blobs.
567567
*/
568568
CV_WRAP void getMemoryConsumption(const std::vector<MatShape>& netInputShapes,
569-
CV_OUT std::vector<int>& layerIds, CV_OUT std::vector<size_t>& weights,
569+
CV_OUT std::vector<int>& layerIds,
570+
CV_OUT std::vector<size_t>& weights,
570571
CV_OUT std::vector<size_t>& blobs) const;
571572
/** @overload */
572573
CV_WRAP void getMemoryConsumption(const MatShape& netInputShape,
573-
CV_OUT std::vector<int>& layerIds, CV_OUT std::vector<size_t>& weights,
574+
CV_OUT std::vector<int>& layerIds,
575+
CV_OUT std::vector<size_t>& weights,
574576
CV_OUT std::vector<size_t>& blobs) const;
575577

576578
/** @brief Enables or disables layer fusion in the network.
577579
* @param fusion true to enable the fusion, false to disable. The fusion is enabled by default.
578580
*/
579581
CV_WRAP void enableFusion(bool fusion);
580582

583+
/** @brief Returns overall time for inference and timings (in ticks) for layers.
584+
* Indexes in returned vector correspond to layers ids. Some layers can be fused with others,
585+
* in this case zero ticks count will be return for that skipped layers.
586+
* @param timings vector for tick timings for all layers.
587+
* @return overall ticks for model inference.
588+
*/
589+
CV_WRAP int64 getPerfProfile(CV_OUT std::vector<double>& timings);
590+
581591
private:
582592
struct Impl;
583593
Ptr<Impl> impl;

modules/dnn/src/dnn.cpp

Lines changed: 45 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
#include <iostream>
4848
#include <sstream>
4949
#include <iterator>
50+
#include <numeric>
5051
#include <opencv2/dnn/shape_utils.hpp>
5152
#include <opencv2/imgproc.hpp>
5253

@@ -633,7 +634,7 @@ struct Net::Impl
633634
inpl.layerInstance = netInputLayer;
634635
layerNameToId.insert(std::make_pair(inpl.name, inpl.id));
635636

636-
lastLayerId = 1;
637+
lastLayerId = 0;
637638
netWasAllocated = false;
638639
fusion = true;
639640
preferableBackend = DNN_BACKEND_DEFAULT;
@@ -656,6 +657,7 @@ struct Net::Impl
656657

657658
bool netWasAllocated;
658659
bool fusion;
660+
std::vector<int64> layersTimings;
659661

660662
void compileHalide()
661663
{
@@ -716,6 +718,8 @@ struct Net::Impl
716718
it = layers.find(0);
717719
CV_Assert(it != layers.end());
718720
it->second.skipFlags[DNN_BACKEND_DEFAULT] = true;
721+
722+
layersTimings.clear();
719723
}
720724

721725
void setUpNet(const std::vector<LayerPin>& blobsToKeep_ = std::vector<LayerPin>())
@@ -1269,6 +1273,8 @@ struct Net::Impl
12691273
allocateLayer(lid, layersShapes);
12701274
}
12711275

1276+
layersTimings.resize(lastLayerId + 1, 0);
1277+
12721278
fuseLayers(blobsToKeep_);
12731279
}
12741280

@@ -1278,11 +1284,16 @@ struct Net::Impl
12781284

12791285
Ptr<Layer> layer = ld.layerInstance;
12801286

1287+
TickMeter tm;
1288+
tm.start();
1289+
12811290
if (preferableBackend == DNN_BACKEND_DEFAULT ||
12821291
!layer->supportBackend(preferableBackend))
12831292
{
12841293
if( !ld.skipFlags[DNN_BACKEND_DEFAULT] )
12851294
layer->forward(ld.inputBlobs, ld.outputBlobs, ld.internals);
1295+
else
1296+
tm.reset();
12861297
}
12871298
else if (!ld.skipFlags[preferableBackend])
12881299
{
@@ -1299,6 +1310,9 @@ struct Net::Impl
12991310
}
13001311
}
13011312

1313+
tm.stop();
1314+
layersTimings[ld.id] = tm.getTimeTicks();
1315+
13021316
ld.flag = 1;
13031317
}
13041318

@@ -1717,45 +1731,39 @@ std::vector<int> Net::getUnconnectedOutLayers() const
17171731
}
17181732

17191733
void Net::getLayersShapes(const ShapesVec& netInputShapes,
1720-
std::vector<int>* layersIds,
1721-
std::vector<ShapesVec>* inLayersShapes,
1722-
std::vector<ShapesVec>* outLayersShapes) const
1734+
std::vector<int>& layersIds,
1735+
std::vector<ShapesVec>& inLayersShapes,
1736+
std::vector<ShapesVec>& outLayersShapes) const
17231737
{
1724-
if ((layersIds || inLayersShapes || outLayersShapes) == false)
1725-
return;
1726-
1727-
if (layersIds) layersIds->clear();
1728-
if (inLayersShapes) inLayersShapes->clear();
1729-
if (outLayersShapes) outLayersShapes->clear();
1738+
layersIds.clear();
1739+
inLayersShapes.clear();
1740+
outLayersShapes.clear();
17301741

17311742
Impl::LayersShapesMap inOutShapes;
17321743
impl->getLayersShapes(netInputShapes, inOutShapes);
17331744

17341745
for(Impl::LayersShapesMap::const_iterator it = inOutShapes.begin();
17351746
it != inOutShapes.end(); it++)
17361747
{
1737-
if (layersIds)
1738-
layersIds->push_back(it->first);
1739-
if (inLayersShapes)
1740-
inLayersShapes->push_back(it->second.in);
1741-
if (outLayersShapes)
1742-
outLayersShapes->push_back(it->second.out);
1748+
layersIds.push_back(it->first);
1749+
inLayersShapes.push_back(it->second.in);
1750+
outLayersShapes.push_back(it->second.out);
17431751
}
17441752
}
17451753

17461754
void Net::getLayersShapes(const MatShape& netInputShape,
1747-
std::vector<int>* layerIds,
1748-
std::vector<ShapesVec>* inLayersShapes,
1749-
std::vector<ShapesVec>* outLayersShapes) const
1755+
std::vector<int>& layerIds,
1756+
std::vector<ShapesVec>& inLayersShapes,
1757+
std::vector<ShapesVec>& outLayersShapes) const
17501758
{
17511759
getLayersShapes(ShapesVec(1, netInputShape),
17521760
layerIds, inLayersShapes, outLayersShapes);
17531761
}
17541762

17551763
void Net::getLayerShapes(const MatShape& netInputShape,
17561764
const int layerId,
1757-
ShapesVec* inLayerShapes,
1758-
ShapesVec* outLayerShapes) const
1765+
ShapesVec& inLayerShapes,
1766+
ShapesVec& outLayerShapes) const
17591767
{
17601768
getLayerShapes(ShapesVec(1, netInputShape),
17611769
layerId, inLayerShapes, outLayerShapes);
@@ -1764,15 +1772,13 @@ void Net::getLayerShapes(const MatShape& netInputShape,
17641772

17651773
void Net::getLayerShapes(const ShapesVec& netInputShapes,
17661774
const int layerId,
1767-
ShapesVec* inLayerShapes,
1768-
ShapesVec* outLayerShapes) const
1775+
ShapesVec& inLayerShapes,
1776+
ShapesVec& outLayerShapes) const
17691777
{
17701778
LayerShapes shapes;
17711779
impl->getLayerShapes(netInputShapes, layerId, shapes);
1772-
if (inLayerShapes)
1773-
*inLayerShapes = shapes.in;
1774-
if (outLayerShapes)
1775-
*outLayerShapes = shapes.out;
1780+
inLayerShapes = shapes.in;
1781+
outLayerShapes = shapes.out;
17761782
}
17771783

17781784
int64 Net::getFLOPS(const std::vector<MatShape>& netInputShapes) const
@@ -1782,7 +1788,7 @@ int64 Net::getFLOPS(const std::vector<MatShape>& netInputShapes) const
17821788
int64 flops = 0;
17831789
std::vector<int> ids;
17841790
std::vector<std::vector<MatShape> > inShapes, outShapes;
1785-
getLayersShapes(netInputShapes, &ids, &inShapes, &outShapes);
1791+
getLayersShapes(netInputShapes, ids, inShapes, outShapes);
17861792
CV_Assert(inShapes.size() == outShapes.size());
17871793
CV_Assert(inShapes.size() == ids.size());
17881794

@@ -1867,8 +1873,8 @@ void Net::getMemoryConsumption(const int layerId,
18671873
weights += weightsBlob.total()*weightsBlob.elemSize();
18681874
}
18691875

1870-
std::vector<MatShape> outLayerShapes;
1871-
getLayerShapes(netInputShapes, layerId, 0, &outLayerShapes);
1876+
ShapesVec inLayerShapes, outLayerShapes;
1877+
getLayerShapes(netInputShapes, layerId, inLayerShapes, outLayerShapes);
18721878
for(int i = 0; i < outLayerShapes.size(); i++)
18731879
{
18741880
blobs += total(outLayerShapes[i]) * sizeof(float);
@@ -1917,9 +1923,9 @@ void Net::getMemoryConsumption(const std::vector<MatShape>& netInputShapes,
19171923
weights.clear();
19181924
blobs.clear();
19191925

1920-
std::vector<std::vector<MatShape> > outLayerShapes;
1926+
std::vector<std::vector<MatShape> > inLayerShapes, outLayerShapes;
19211927

1922-
getLayersShapes(netInputShapes, &layerIds, 0, &outLayerShapes);
1928+
getLayersShapes(netInputShapes, layerIds, inLayerShapes, outLayerShapes);
19231929

19241930
for(int i = 0; i < layerIds.size(); i++)
19251931
{
@@ -1968,6 +1974,13 @@ void Net::setHalideScheduler(const String& scheduler)
19681974
impl->halideConfigFile = scheduler;
19691975
}
19701976

1977+
int64 Net::getPerfProfile(std::vector<double>& timings)
1978+
{
1979+
timings = std::vector<double>(impl->layersTimings.begin() + 1, impl->layersTimings.end());
1980+
int64 total = std::accumulate(timings.begin(), timings.end(), 0);
1981+
return total;
1982+
}
1983+
19711984
//////////////////////////////////////////////////////////////////////////
19721985

19731986
Importer::~Importer() {}

modules/java/generator/src/cpp/listconverters.cpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,21 @@ void Copy_vector_String_to_List(JNIEnv* env, std::vector<cv::String>& vs, jobjec
5656
env->CallBooleanMethod(list, m_add, element);
5757
env->DeleteLocalRef(element);
5858
}
59-
}
59+
}
60+
61+
#if defined(HAVE_OPENCV_DNN)
62+
void Copy_vector_MatShape_to_List(JNIEnv* env, std::vector<cv::dnn::MatShape>& vs, jobject list)
63+
{
64+
static jclass juArrayList = ARRAYLIST(env);
65+
jmethodID m_clear = LIST_CLEAR(env, juArrayList);
66+
jmethodID m_add = LIST_ADD(env, juArrayList);
67+
68+
env->CallVoidMethod(list, m_clear);
69+
for (std::vector<cv::dnn::MatShape>::iterator it = vs.begin(); it != vs.end(); ++it)
70+
{
71+
jstring element = env->NewStringUTF("");
72+
env->CallBooleanMethod(list, m_add, element);
73+
env->DeleteLocalRef(element);
74+
}
75+
}
76+
#endif

modules/java/generator/src/cpp/listconverters.hpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,9 @@ std::vector<cv::String> List_to_vector_String(JNIEnv* env, jobject list);
1616

1717
void Copy_vector_String_to_List(JNIEnv* env, std::vector<cv::String>& vs, jobject list);
1818

19-
#endif /* LISTCONVERTERS_HPP */
19+
#if defined(HAVE_OPENCV_DNN)
20+
#include "opencv2/dnn.hpp"
21+
void Copy_vector_MatShape_to_List(JNIEnv* env, std::vector<cv::dnn::MatShape>& vs, jobject list);
22+
#endif
23+
24+
#endif /* LISTCONVERTERS_HPP */

samples/dnn/ssd_mobilenet_object_detection.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -101,17 +101,18 @@ int main(int argc, char** argv)
101101
//! [Prepare blob]
102102

103103
//! [Set input blob]
104-
net.setInput(inputBlob, "data"); //set the network input
104+
net.setInput(inputBlob, "data"); //set the network input
105105
//! [Set input blob]
106106

107-
TickMeter tm;
108-
tm.start();
109107
//! [Make forward pass]
110-
Mat detection = net.forward("detection_out"); //compute output
111-
tm.stop();
112-
cout << "Inference time, ms: " << tm.getTimeMilli() << endl;
108+
Mat detection = net.forward("detection_out"); //compute output
113109
//! [Make forward pass]
114110

111+
std::vector<double> layersTimings;
112+
double freq = getTickFrequency() / 1000;
113+
double time = net.getPerfProfile(layersTimings) / freq;
114+
cout << "Inference time, ms: " << time << endl;
115+
115116
Mat detectionMat(detection.size[2], detection.size[3], CV_32F, detection.ptr<float>());
116117

117118
frame = frame(crop);

0 commit comments

Comments
 (0)