a nice patch that makes the three most CPU-hogging functions (as reported by Shark) essentially free and reduces memory overhead by 8 bytes per piece per torrent. Lots of asserts for extra testing fun.

This commit is contained in:
Charles Kerr 2007-07-28 15:43:34 +00:00
parent 157d20cee1
commit 79a0081092
9 changed files with 207 additions and 186 deletions

View File

@ -40,6 +40,11 @@ struct tr_completion_s
/* a block is complete if and only if we have it */
uint16_t * completeBlocks;
uint8_t doneDirty;
uint64_t doneHave;
uint64_t doneTotal;
uint64_t completeHave;
};
tr_completion_t * tr_cpInit( tr_torrent_t * tor )
@ -75,6 +80,60 @@ void tr_cpReset( tr_completion_t * cp )
memset( cp->blockDownloaders, 0, tor->blockCount );
tr_bitfieldClear( cp->pieceBitfield );
memset( cp->completeBlocks, 0, sizeof(uint16_t) * tor->info.pieceCount );
cp->doneDirty = TRUE;
cp->doneHave = 0;
cp->doneTotal = 0;
cp->completeHave = 0;
}
/**
***
**/
static void
tr_cpEnsureDoneValid( const tr_completion_t * ccp )
{
const tr_torrent_t * tor = ccp->tor;
const tr_info_t * info = &tor->info;
uint64_t have=0, total=0;
int i;
tr_completion_t * cp ;
if( !ccp->doneDirty )
return;
/* too bad C doesn't have 'mutable' */
cp = (tr_completion_t*) ccp;
cp->doneDirty = FALSE;
for( i=0; i<info->pieceCount; ++i ) {
if( !info->pieces[i].dnd ) {
total += info->pieceSize;
have += cp->completeBlocks[ i ];
}
}
have *= tor->blockSize;
/* the last piece/block is probably smaller than the others */
if( !info->pieces[info->pieceCount-1].dnd ) {
total -= ( info->pieceSize - ( info->totalSize % info->pieceSize ) );
if( tr_cpBlockIsComplete( cp, tor->blockCount-1 ) )
have -= ( tor->blockSize - ( info->totalSize % tor->blockSize ) );
}
assert( have <= total );
assert( total <= info->totalSize );
cp->doneHave = have;
cp->doneTotal = total;
}
void
tr_cpInvalidateDND ( tr_completion_t * cp )
{
cp->doneDirty = TRUE;
}
int tr_cpPieceHasAllBlocks( const tr_completion_t * cp, int piece )
@ -84,7 +143,7 @@ int tr_cpPieceHasAllBlocks( const tr_completion_t * cp, int piece )
int tr_cpPieceIsComplete( const tr_completion_t * cp, int piece )
{
return cp->completeBlocks[piece] >= TR_BLOCKS_IN_PIECE(cp->tor,piece);
return cp->completeBlocks[piece] >= tr_torPieceCountBlocks(cp->tor,piece);
}
const tr_bitfield_t * tr_cpPieceBitfield( const tr_completion_t * cp )
@ -95,32 +154,40 @@ const tr_bitfield_t * tr_cpPieceBitfield( const tr_completion_t * cp )
void tr_cpPieceAdd( tr_completion_t * cp, int piece )
{
const tr_torrent_t * tor = cp->tor;
const int n_blocks = TR_BLOCKS_IN_PIECE(tor,piece);
const int startBlock = TOR_PIECE_FIRST_BLOCK(tor,piece);
const int endBlock = startBlock + n_blocks;
const int start = tr_torPieceFirstBlock(tor,piece);
const int end = start + tr_torPieceCountBlocks(tor,piece);
int i;
cp->completeBlocks[piece] = n_blocks;
tr_bitfieldAddRange( cp->blockBitfield, startBlock, endBlock );
tr_bitfieldAdd( cp->pieceBitfield, piece );
for( i=start; i<end; ++i )
tr_cpBlockAdd( cp, i );
}
void tr_cpPieceRem( tr_completion_t * cp, int piece )
{
const tr_torrent_t * tor = cp->tor;
const int n_blocks = TR_BLOCKS_IN_PIECE(tor,piece);
const int startBlock = TOR_PIECE_FIRST_BLOCK(tor,piece);
const int endBlock = startBlock + n_blocks;
const int start = tr_torPieceFirstBlock(tor,piece);
const int end = start + tr_torPieceCountBlocks(tor,piece);
int block;
assert( cp != NULL );
assert( 0 <= piece );
assert( piece < tor->info.pieceCount );
assert( 0 <= startBlock );
assert( startBlock < tor->blockCount );
assert( startBlock <= endBlock );
assert( endBlock <= tor->blockCount );
assert( 0 <= start );
assert( start < tor->blockCount );
assert( start <= end );
assert( end <= tor->blockCount );
for( block=start; block<end; ++block ) {
if( tr_cpBlockIsComplete( cp, block ) ) {
const int blockSize = tr_torBlockCountBytes( tor, block );
cp->completeHave -= blockSize;
if( !tor->info.pieces[piece].dnd )
cp->doneHave -= blockSize;
}
}
cp->completeBlocks[piece] = 0;
tr_bitfieldRemRange ( cp->blockBitfield, startBlock, endBlock );
tr_bitfieldRemRange ( cp->blockBitfield, start, end );
tr_bitfieldRem( cp->pieceBitfield, piece );
}
@ -140,20 +207,27 @@ int tr_cpBlockIsComplete( const tr_completion_t * cp, int block )
return tr_bitfieldHas( cp->blockBitfield, block );
}
void tr_cpBlockAdd( tr_completion_t * cp, int block )
void
tr_cpBlockAdd( tr_completion_t * cp, int block )
{
const tr_torrent_t * tor = cp->tor;
if( !tr_cpBlockIsComplete( cp, block ) )
{
const int piece = TOR_BLOCK_PIECE(tor, block);
const int piece = tr_torBlockPiece( tor, block );
const int blockSize = tr_torBlockCountBytes( tor, block );
++cp->completeBlocks[piece];
if( cp->completeBlocks[piece] == TR_BLOCKS_IN_PIECE(tor,piece) )
if( cp->completeBlocks[piece] == tr_torPieceCountBlocks( tor, piece ) )
tr_bitfieldAdd( cp->pieceBitfield, piece );
tr_bitfieldAdd( cp->blockBitfield, block );
cp->completeHave += blockSize;
if( !tor->info.pieces[piece].dnd )
cp->doneHave += blockSize;
}
}
@ -183,7 +257,7 @@ float tr_cpPercentBlocksInPiece( const tr_completion_t * cp, int piece )
{
assert( cp != NULL );
return cp->completeBlocks[piece] / (double)TR_BLOCKS_IN_PIECE(cp->tor,piece);
return (double)cp->completeBlocks[piece] / tr_torPieceCountBlocks(cp->tor,piece);
}
int
@ -192,8 +266,8 @@ tr_cpMissingBlocksForPiece( const tr_completion_t * cp, int piece )
int i;
int n;
const tr_torrent_t * tor = cp->tor;
const int start = TOR_PIECE_FIRST_BLOCK(tor,piece);
const int end = start + TR_BLOCKS_IN_PIECE(tor,piece);
const int start = tr_torPieceFirstBlock(tor,piece);
const int end = start + tr_torPieceCountBlocks(tor,piece);
n = 0;
for( i = start; i < end; ++i )
@ -207,8 +281,8 @@ int tr_cpMissingBlockInPiece( const tr_completion_t * cp, int piece )
{
int i;
const tr_torrent_t * tor = cp->tor;
const int start = TOR_PIECE_FIRST_BLOCK(tor,piece);
const int end = start + TR_BLOCKS_IN_PIECE(tor,piece);
const int start = tr_torPieceFirstBlock(tor,piece);
const int end = start + tr_torPieceCountBlocks(tor,piece);
for( i = start; i < end; ++i )
if( !tr_cpBlockIsComplete( cp, i ) && !cp->blockDownloaders[i] )
@ -221,93 +295,46 @@ int tr_cpMissingBlockInPiece( const tr_completion_t * cp, int piece )
****
***/
cp_status_t
tr_cpGetStatus ( const tr_completion_t * cp )
float
tr_cpPercentComplete ( const tr_completion_t * cp )
{
int i;
int ret = TR_CP_COMPLETE;
const tr_info_t * info;
assert( cp != NULL );
assert( cp->tor != NULL );
info = &cp->tor->info;
for( i=0; i<info->pieceCount; ++i ) {
if( tr_cpPieceIsComplete( cp, i ) )
continue;
if( !info->pieces[i].dnd )
return TR_CP_INCOMPLETE;
ret = TR_CP_DONE;
}
return ret;
return (double)cp->completeHave / cp->tor->info.totalSize;
}
uint64_t
tr_cpLeftUntilComplete ( const tr_completion_t * cp )
{
int i;
uint64_t b=0;
const tr_torrent_t * tor;
const tr_info_t * info;
assert( cp != NULL );
assert( cp->tor != NULL );
tor = cp->tor;
info = &tor->info;
for( i=0; i<info->pieceCount; ++i )
if( !tr_cpPieceIsComplete( cp, i ) )
b += ( TR_BLOCKS_IN_PIECE(tor,i) - cp->completeBlocks[ i ] );
b *= tor->blockSize;
if( tor->blockCount && !tr_cpBlockIsComplete( cp, tor->blockCount - 1 ) )
b -= (tor->blockSize - (tor->info.totalSize % tor->blockSize));
return b;
}
void
tr_cpDoneStats( const tr_completion_t * cp ,
uint64_t * setmeHaveBytes,
uint64_t * setmeTotalBytes )
{
const tr_torrent_t * tor = cp->tor;
const tr_info_t * info = &tor->info;
uint64_t have=0, total=0;
int i;
for( i=0; i<info->pieceCount; ++i ) {
if( !info->pieces[i].dnd ) {
total += info->pieceSize;
have += cp->completeBlocks[ i ];
}
}
have *= tor->blockSize;
/* the last piece/block is probably smaller than the others */
if( !info->pieces[info->pieceCount-1].dnd ) {
total -= ( info->pieceSize - ( info->totalSize % info->pieceSize ) );
if( tr_cpBlockIsComplete( cp, tor->blockCount-1 ) )
have -= ( tor->blockSize - ( info->totalSize % tor->blockSize ) );
}
assert( have <= total );
assert( total <= info->totalSize );
*setmeHaveBytes = have;
*setmeTotalBytes = total;
return cp->tor->info.totalSize - cp->completeHave;
}
float
tr_cpPercentComplete ( const tr_completion_t * cp )
tr_cpPercentDone( const tr_completion_t * cp )
{
const uint64_t tilComplete = tr_cpLeftUntilComplete( cp );
const uint64_t total = cp->tor->info.totalSize;
const float f = 1.0 - (double)tilComplete / total;
return MAX(0.0, f);
tr_cpEnsureDoneValid( cp );
return (double)cp->doneHave / cp->doneTotal;
}
uint64_t
tr_cpLeftUntilDone ( const tr_completion_t * cp )
{
tr_cpEnsureDoneValid( cp );
return cp->doneTotal - cp->doneHave;
}
cp_status_t
tr_cpGetStatus ( const tr_completion_t * cp )
{
if( cp->completeHave >= cp->tor->info.totalSize )
return TR_CP_COMPLETE;
tr_cpEnsureDoneValid( cp );
if( cp->doneHave >= cp->doneTotal )
return TR_CP_DONE;
return TR_CP_INCOMPLETE;
}
uint64_t

View File

@ -34,14 +34,12 @@ void tr_cpReset( tr_completion_t * );
/* General */
cp_status_t tr_cpGetStatus ( const tr_completion_t * );
uint64_t tr_cpDownloadedValid( const tr_completion_t * );
uint64_t tr_cpLeftUntilComplete( const tr_completion_t * );
uint64_t tr_cpLeftUntilDone( const tr_completion_t * );
float tr_cpPercentComplete( const tr_completion_t * );
void tr_cpDoneStats( const tr_completion_t * cp,
uint64_t * setmeHaveBytes,
uint64_t * setmeTotalBytes );
float tr_cpPercentDone( const tr_completion_t * );
void tr_cpInvalidateDND ( tr_completion_t * );
/* Pieces */
int tr_cpPieceHasAllBlocks( const tr_completion_t *, int piece );

View File

@ -81,7 +81,7 @@ findFileLocation ( const tr_torrent_t * tor,
assert ( 0<=pieceIndex && pieceIndex < info->pieceCount );
assert ( 0<=tor->info.pieceSize );
assert ( pieceOffset < tr_pieceSize(pieceIndex) );
assert ( pieceOffset < tr_torPieceCountBytes( tor, pieceIndex ) );
assert ( piecePos < info->totalSize );
for ( i=0; info->files[i].length<=piecePos; ++i )
@ -139,7 +139,7 @@ readOrWritePiece ( tr_torrent_t * tor,
const tr_info_t * info = &tor->info;
assert( 0<=pieceIndex && pieceIndex<tor->info.pieceCount );
assert( buflen <= (size_t) tr_pieceSize( pieceIndex ) );
assert( buflen <= (size_t) tr_torPieceCountBytes( tor, pieceIndex ) );
findFileLocation ( tor, pieceIndex, pieceOffset, &fileIndex, &fileOffset );
@ -194,7 +194,7 @@ tr_ioRecalculateHash ( tr_torrent_t * tor,
assert( 0<=pieceIndex && pieceIndex<tor->info.pieceCount );
info = &tor->info;
n = tr_pieceSize( pieceIndex );
n = tr_torPieceCountBytes( tor, pieceIndex );
buf = malloc( n );
ret = readOrWritePiece ( tor, TR_IO_READ, pieceIndex, 0, buf, n );

View File

@ -121,21 +121,23 @@ void tr_torrentReaderUnlock ( const tr_torrent_t * );
void tr_torrentWriterLock ( tr_torrent_t * );
void tr_torrentWriterUnlock ( tr_torrent_t * );
/* get the index of this piece's first block */
#define tr_torPieceFirstBlock(tor,piece) ( (piece) * (tor)->blockCountInPiece )
#define TOR_BLOCK_PIECE(tor,block) \
( (block) / ( (tor)->info.pieceSize / (tor)->blockSize ) )
/* what piece index is this block in? */
#define tr_torBlockPiece(tor,block) ( (block) / (tor)->blockCountInPiece )
#define TOR_PIECE_FIRST_BLOCK(tor,piece) \
( (tor)->info.pieces[(piece)].firstBlock )
/* how many blocks are in this piece? */
#define tr_torPieceCountBlocks(tor,piece) \
( ((piece)==((tor)->info.pieceCount-1)) ? (tor)->blockCountInLastPiece : (tor)->blockCountInPiece )
#define TR_BLOCKS_IN_PIECE(tor,piece) \
( (tor)->info.pieces[(piece)].blockCount )
/* how many bytes are in this piece? */
#define tr_torPieceCountBytes(tor,piece) \
( ((piece)==((tor)->info.pieceCount-1)) ? (tor)->lastPieceSize : (tor)->info.pieceSize )
#define tr_blockSize(a) _tr_blockSize(tor,a)
int _tr_blockSize( const tr_torrent_t * tor, int block );
#define tr_pieceSize(a) _tr_pieceSize(tor,a)
int _tr_pieceSize( const tr_torrent_t * tor, int piece );
/* how many bytes are in this block? */
#define tr_torBlockCountBytes(tor,block) \
( ((block)==((tor)->blockCount-1)) ? (tor)->lastBlockSize : (tor)->blockSize )
#define tr_block(a,b) _tr_block(tor,a,b)
int _tr_block( const tr_torrent_t * tor, int index, int begin );
@ -184,6 +186,12 @@ struct tr_torrent_s
/* How many bytes we ask for per request */
int blockSize;
int blockCount;
int lastBlockSize;
int lastPieceSize;
int blockCountInPiece;
int blockCountInLastPiece;
tr_completion_t * completion;

View File

@ -689,8 +689,8 @@ writeEnd:
for( ; openSlots>0 && piecesLeft>0; --piecesLeft, p=(p+1)%poolSize )
{
const int piece = pool[p];
const int firstBlock = TOR_PIECE_FIRST_BLOCK( tor, piece );
const int n = TR_BLOCKS_IN_PIECE( tor, piece );
const int firstBlock = tr_torPieceFirstBlock( tor, piece );
const int n = tr_torPieceCountBlocks( tor, piece );
const int end = firstBlock + n;
int block;
for( block=firstBlock; openSlots>0 && block<end; ++block )

View File

@ -304,7 +304,7 @@ static void sendRequest( tr_torrent_t * tor, tr_peer_t * peer, int block )
r->index = block / ( inf->pieceSize / tor->blockSize );
r->begin = ( block % ( inf->pieceSize / tor->blockSize ) ) *
tor->blockSize;
r->length = tr_blockSize( block );
r->length = tr_torBlockCountBytes( tor, block );
(peer->inRequestCount)++;
/* Build the "ask" message */

View File

@ -223,7 +223,7 @@ static int parseRequest( tr_torrent_t * tor, tr_peer_t * peer,
peer_dbg( "GET request, invalid index" );
return TR_ERROR_ASSERT;
}
if( tr_pieceSize( index ) < begin + length )
if( tr_torPieceCountBytes( tor, index ) < begin + length )
{
peer_dbg( "GET request, invalid begin/length" );
return TR_ERROR_ASSERT;
@ -301,7 +301,7 @@ static int parsePiece( tr_torrent_t * tor, tr_peer_t * peer,
peer_dbg( "GET piece, invalid index" );
return TR_ERROR_ASSERT;
}
if( tr_pieceSize( index ) < begin + len - 8 )
if( tr_torPieceCountBytes( tor, index ) < begin + len - 8 )
{
peer_dbg( "GET piece, invalid begin/length" );
return TR_ERROR_ASSERT;
@ -315,9 +315,9 @@ static int parsePiece( tr_torrent_t * tor, tr_peer_t * peer,
updateRequests( peer, index, begin );
/* Sanity checks */
if( len - 8 != tr_blockSize( block ) )
if( len - 8 != tr_torBlockCountBytes( tor, block ) )
{
peer_dbg( "wrong size (expecting %d)", tr_blockSize( block ) );
peer_dbg( "wrong size (expecting %d)", tr_torBlockCountBytes( tor, block ) );
return TR_ERROR_ASSERT;
}
if( tr_cpBlockIsComplete( tor->completion, block ) )
@ -405,7 +405,7 @@ static int parseCancel( tr_torrent_t * tor, tr_peer_t * peer,
peer_dbg( "GET cancel, invalid index" );
return TR_ERROR_ASSERT;
}
if( tr_pieceSize( index ) < begin + length )
if( tr_torPieceCountBytes( tor, index ) < begin + length )
{
peer_dbg( "GET cancel, invalid begin/length" );
return TR_ERROR_ASSERT;

View File

@ -22,6 +22,7 @@
* DEALINGS IN THE SOFTWARE.
*****************************************************************************/
#include <assert.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
@ -168,28 +169,7 @@ tr_torrentInitFilePieces( tr_torrent_t * tor )
}
for( i=0; i<tor->info.pieceCount; ++i )
{
tr_piece_t * piece = tor->info.pieces + i;
uint64_t lastByte;
int lastBlock;
if( i == (tor->info.pieceCount-1))
lastByte = tor->info.totalSize - 1;
else {
lastByte = i + 1;
lastByte *= tor->info.pieceSize;
--lastByte;
}
lastBlock = lastByte / tor->blockSize;
piece->priority = calculatePiecePriority( tor, i );
piece->firstBlock = i * (tor->info.pieceSize / tor->blockSize);
piece->blockCount = lastBlock + 1 - piece->firstBlock;
assert( 0 <= piece->firstBlock );
assert( piece->firstBlock <= lastBlock );
assert( lastBlock < tor->blockCount );
assert( piece->firstBlock + piece->blockCount <= tor->blockCount );
}
tor->info.pieces[i].priority = calculatePiecePriority( tor, i );
}
static void torrentThreadLoop( void * );
@ -202,8 +182,10 @@ torrentRealInit( tr_handle_t * h,
{
int i;
uint64_t loaded;
uint64_t t;
char name[512];
tr_bitfield_t * uncheckedPieces;
tr_info_t * info = &tor->info;
tor->info.flags |= flags;
@ -226,10 +208,43 @@ torrentRealInit( tr_handle_t * h,
tor->pexDisabled = 0;
/* Block size: usually 16 kib, or less if we have to */
tor->blockSize = MIN( tor->info.pieceSize, 1 << 14 );
tor->blockCount = ( tor->info.totalSize + tor->blockSize - 1 ) /
tor->blockSize;
/**
* Decide on a block size. constraints:
* (1) most clients decline requests over 16 KiB
* (2) pieceSize must be a multiple of block size
*/
tor->blockSize = info->pieceSize;
while( tor->blockSize > (1024*16) )
tor->blockSize /= 2;
tor->lastPieceSize = info->totalSize % info->pieceSize;
tor->lastBlockSize = info->totalSize % tor->blockSize;
tor->blockCount =
( info->totalSize + tor->blockSize - 1 ) / tor->blockSize;
tor->blockCountInPiece =
info->pieceSize / tor->blockSize;
tor->blockCountInLastPiece =
( tor->lastPieceSize + tor->blockSize - 1 ) / tor->blockSize;
/* check our work */
assert( ( info->pieceSize % tor->blockSize ) == 0 );
t = info->pieceCount - 1;
t *= info->pieceSize;
t += tor->lastPieceSize;
assert( t == info->totalSize );
t = tor->blockCount - 1;
t *= tor->blockSize;
t += tor->lastBlockSize;
assert( t == info->totalSize );
t = info->pieceCount - 1;
t *= tor->blockCountInPiece;
t += tor->blockCountInLastPiece;
assert( t == (uint64_t)tor->blockCount );
tor->completion = tr_cpInit( tor );
tr_torrentInitFilePieces( tor );
@ -596,7 +611,6 @@ tr_torrentStat( tr_torrent_t * tor )
tr_stat_t * s;
tr_tracker_t * tc;
int i;
uint64_t doneHave, doneTotal;
tr_torrentReaderLock( tor );
@ -639,9 +653,8 @@ tr_torrentStat( tr_torrent_t * tor )
s->percentComplete = tr_cpPercentComplete ( tor->completion );
tr_cpDoneStats( tor->completion, &doneHave, &doneTotal );
s->percentDone = (float)doneHave / (float)doneTotal;
s->left = doneTotal - doneHave;
s->percentDone = tr_cpPercentDone( tor->completion );
s->left = tr_cpLeftUntilDone( tor->completion );
if( tor->uncheckedPieces )
s->status = tor->runStatus==TR_RUN_CHECKING
@ -721,8 +734,8 @@ fileBytesCompleted ( const tr_torrent_t * tor, int fileIndex )
assert( (int)firstBlock < tor->blockCount );
assert( (int)lastBlock < tor->blockCount );
assert( firstBlock <= lastBlock );
assert( (int)TOR_BLOCK_PIECE( tor, firstBlock ) == file->firstPiece );
assert( (int)TOR_BLOCK_PIECE( tor, lastBlock ) == file->lastPiece );
assert( (int)tr_torBlockPiece( tor, firstBlock ) == file->firstPiece );
assert( (int)tr_torBlockPiece( tor, lastBlock ) == file->lastPiece );
if( firstBlock == lastBlock )
{
@ -1383,6 +1396,8 @@ tr_torrentSetFileDL( tr_torrent_t * tor,
tor->info.pieces[i].dnd = dnd;
}
tr_cpInvalidateDND ( tor->completion );
tor->fastResumeDirty = TRUE;
tr_torrentWriterUnlock( tor );
@ -1403,31 +1418,6 @@ tr_torrentSetFileDLs ( tr_torrent_t * tor,
****
***/
int _tr_blockSize( const tr_torrent_t * tor, int block )
{
const tr_info_t * inf = &tor->info;
int dummy;
if( block != tor->blockCount - 1 ||
!( dummy = inf->totalSize % tor->blockSize ) )
{
return tor->blockSize;
}
return dummy;
}
int _tr_pieceSize( const tr_torrent_t * tor, int piece )
{
const tr_info_t * inf = &tor->info;
if( piece < inf->pieceCount - 1 ||
!( inf->totalSize % inf->pieceSize ) )
{
return inf->pieceSize;
}
return inf->totalSize % inf->pieceSize;
}
int _tr_block( const tr_torrent_t * tor, int index, int begin )
{
const tr_info_t * inf = &tor->info;

View File

@ -515,8 +515,6 @@ typedef struct tr_piece_s
uint8_t hash[SHA_DIGEST_LENGTH]; /* pieces hash */
int8_t priority; /* TR_PRI_HIGH, _NORMAL, or _LOW */
int8_t dnd; /* nonzero if the piece shouldn't be downloaded */
int firstBlock; /* this piece's first byte is in this block */
int blockCount; /* number of blocks this piece is in */
}
tr_piece_t;