1 /*****************************************************************************
2 * Copyright (C) 2013 x265 project
4 * Authors: Steve Borho <steve@borho.org>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
20 * This program is also available under a commercial proprietary license.
21 * For more information, contact us at license @ x265.com
22 *****************************************************************************/
25 #include "threadpool.h"
26 #include "wavefront.h"
27 #include "threading.h"
40 memset(digest
, 0, sizeof(digest
));
43 unsigned char digest
[16];
48 RowData() : active(false), curCol(0) {}
55 // Create a fake frame class with manufactured data in each CU block. We
56 // need to create an MD5 hash such that each CU's hash includes the hashes
57 // of the blocks that would have HEVC data dependencies (left, top-left,
58 // top, top-right). This will give us one deterministic output hash. We
59 // then generate the same hash using the thread pool and wave-front parallelism
60 // to verify the thread-pool behavior and the wave-front schedule data
62 class MD5Frame
: public WaveFront
74 MD5Frame(ThreadPool
*pool
) : WaveFront(pool
), cu(0), row(0) {}
78 // ensure no threads are lingering on FindJob() before allowing
79 // this object's vtable to be destroyed
86 void initialize(int cols
, int rows
);
90 void processRow(int row
, int threadid
);
93 void MD5Frame::initialize(int cols
, int rows
)
95 this->cu
= new CUData
[rows
* cols
];
96 this->row
= new RowData
[rows
];
100 if (!this->WaveFront::init(rows
))
102 assert(!"Unable to initialize job queue");
106 void MD5Frame::encode()
108 this->JobProvider::enqueue();
110 this->WaveFront::enqueueRow(0);
112 // NOTE: When EnableRow after enqueueRow at first row, we'd better call pokeIdleThread, it will release a thread to do job
113 this->WaveFront::enableRow(0);
114 this->m_pool
->pokeIdleThread();
116 this->complete
.wait();
118 this->JobProvider::dequeue();
120 unsigned int *outdigest
= (unsigned int*)this->cu
[this->numrows
* this->numcols
- 1].digest
;
122 std::stringstream ss
;
124 for (int i
= 0; i
< 4; i
++)
126 ss
<< std::hex
<< outdigest
[i
];
129 if (ss
.str().compare("da667b741a7a9d0ee862158da2dd1882"))
130 std::cout
<< "Bad hash: " << ss
.str() << std::endl
;
133 void MD5Frame::processRow(int rownum
, int)
135 // Called by worker thread
136 RowData
&curRow
= this->row
[rownum
];
138 assert(rownum
< this->numrows
&& rownum
>= 0);
139 assert(curRow
.curCol
< this->numcols
);
141 while (curRow
.curCol
< this->numcols
)
143 int id
= rownum
* this->numcols
+ curRow
.curCol
;
144 CUData
&curCTU
= this->cu
[id
];
147 // * Fake CTU processing *
148 PPAStartCpuEventFunc(encode_block
);
149 memset(curCTU
.digest
, id
, sizeof(curCTU
.digest
));
150 hash
.update(curCTU
.digest
, sizeof(curCTU
.digest
));
151 if (curRow
.curCol
> 0)
152 hash
.update(this->cu
[id
- 1].digest
, sizeof(curCTU
.digest
));
156 if (curRow
.curCol
> 0)
157 hash
.update(this->cu
[id
- this->numcols
- 1].digest
, sizeof(curCTU
.digest
));
159 hash
.update(this->cu
[id
- this->numcols
].digest
, sizeof(curCTU
.digest
));
160 if (curRow
.curCol
< this->numcols
- 1)
161 hash
.update(this->cu
[id
- this->numcols
+ 1].digest
, sizeof(curCTU
.digest
));
164 hash
.finalize(curCTU
.digest
);
165 PPAStopCpuEventFunc(encode_block
);
169 if (curRow
.curCol
>= 2 && rownum
< this->numrows
- 1)
171 ScopedLock
below(this->row
[rownum
+ 1].lock
);
173 if (this->row
[rownum
+ 1].active
== false &&
174 this->row
[rownum
+ 1].curCol
+ 2 <= curRow
.curCol
)
176 // set active indicator so row is only enqueued once
177 // row stays marked active until blocked or done
178 this->row
[rownum
+ 1].active
= true;
179 this->WaveFront::enqueueRow(rownum
+ 1);
180 this->WaveFront::enableRow(rownum
+ 1);
184 ScopedLock
self(curRow
.lock
);
187 curRow
.curCol
< this->numcols
- 1 &&
188 this->row
[rownum
- 1].curCol
< curRow
.curCol
+ 2)
190 // row is blocked, quit job
191 curRow
.active
= false;
198 if (rownum
== this->numrows
- 1)
199 this->complete
.trigger();
202 int main(int, char **)
208 pool
= ThreadPool::allocThreadPool(1);
210 MD5Frame
frame(pool
);
211 frame
.initialize(60, 40);
215 pool
= ThreadPool::allocThreadPool(2);
217 MD5Frame
frame(pool
);
218 frame
.initialize(60, 40);
222 pool
= ThreadPool::allocThreadPool(4);
224 MD5Frame
frame(pool
);
225 frame
.initialize(60, 40);
229 pool
= ThreadPool::allocThreadPool(8);
231 MD5Frame
frame(pool
);
232 frame
.initialize(60, 40);