From 79a33ca2ac976e70f0befb6317785a99f9fd23e8 Mon Sep 17 00:00:00 2001 From: Thomas Schmitt Date: Sun, 15 Nov 2009 15:30:26 +0000 Subject: [PATCH] New API calls burn_write_opts_set_dvd_obs(), burn_write_opts_set_stdio_fsync() --- cdrskin/cdrskin_timestamp.h | 2 +- libburn/libburn.h | 29 +++++++ libburn/options.c | 21 +++++ libburn/options.h | 17 ++++- libburn/write.c | 148 ++++++++++++++++++++++++++++++++++-- 5 files changed, 210 insertions(+), 7 deletions(-) diff --git a/cdrskin/cdrskin_timestamp.h b/cdrskin/cdrskin_timestamp.h index b2f5af4..ab8d348 100644 --- a/cdrskin/cdrskin_timestamp.h +++ b/cdrskin/cdrskin_timestamp.h @@ -1 +1 @@ -#define Cdrskin_timestamP "2009.11.15.152541" +#define Cdrskin_timestamP "2009.11.15.153140" diff --git a/libburn/libburn.h b/libburn/libburn.h index 1a46f9e..5ea49ae 100644 --- a/libburn/libburn.h +++ b/libburn/libburn.h @@ -767,6 +767,9 @@ void burn_set_verbosity(int level); This call can be made at any time - even before burn_initialize(). It is in effect for all active drives and currently not very thread safe for multiple drives. + + >>> ??? Shouldn't the file path with bit1 be adjustable ? + @param flag Bitfield for control purposes. The default is 0. bit0= log to file /tmp/libburn_sg_command_log bit1= log to stderr @@ -2119,6 +2122,32 @@ void burn_write_opts_set_force(struct burn_write_opts *opts, int use_force); void burn_write_opts_set_stream_recording(struct burn_write_opts *opts, int value); +/* ts A91115 */ +/** Overrides the write chunk size for DVD and BD media which is normally + determined according to media type and setting of stream recording. + A chunk size of 64 KB may improve throughput with bus systems which show + latency problems. + @param opts The write opts to change + @param obs Number of bytes which shall be sent by a single write command. + 0 means automatic size, 32768 and 65336 are the only other + accepted sizes for now. + @since 0.7.4 +*/ +void burn_write_opts_set_dvd_obs(struct burn_write_opts *opts, int obs); + +/* ts A91115 */ +/** Sets the rythm by which stdio pseudo drives force their output data to + be consumed by the receiving storage device. This forcing keeps the memory + from being clogged with lots of pending data for slow devices. + @param opts The write opts to change + @param rythm Number of 2KB output blocks after which fsync(2) is + performed. -1 means no fsync(), 0 means default, + elsewise the value must be >= 32. + Default is currently 8192 = 16 MB. + @since 0.7.4 +*/ +void burn_write_opts_set_stdio_fsync(struct burn_write_opts *opts, int rythm); + /** Sets whether to read in raw mode or not @param opts The read opts to change diff --git a/libburn/options.c b/libburn/options.c index b48a1b5..070502b 100644 --- a/libburn/options.c +++ b/libburn/options.c @@ -39,6 +39,8 @@ struct burn_write_opts *burn_write_opts_new(struct burn_drive *drive) opts->fill_up_media = 0; opts->force_is_set = 0; opts->do_stream_recording = 0; + opts->dvd_obs_override = 0; + opts->stdio_fsync_size = Libburn_stdio_fsync_limiT; opts->has_mediacatalog = 0; opts->format = BURN_CDROM; opts->multi = 0; @@ -389,6 +391,25 @@ void burn_write_opts_set_stream_recording(struct burn_write_opts *opts, } +/* ts A91115: API */ +void burn_write_opts_set_dvd_obs(struct burn_write_opts *opts, int obs) +{ + if (obs != 0 && obs != 32 * 1024 && obs != 64 * 1024) + return; + opts->dvd_obs_override = obs; +} + + +/* ts A91115: API */ +void burn_write_opts_set_stdio_fsync(struct burn_write_opts *opts, int rythm) +{ + if (rythm == -1) + opts->stdio_fsync_size = 0; + else if (rythm == 0) + opts->stdio_fsync_size = Libburn_stdio_fsync_limiT; + else if (rythm >= 32) + opts->stdio_fsync_size = rythm; +} /* ts A70901: API */ diff --git a/libburn/options.h b/libburn/options.h index 17c961d..9fc9db0 100644 --- a/libburn/options.h +++ b/libburn/options.h @@ -51,9 +51,19 @@ struct burn_write_opts /* ts A80412 : whether to use WRITE12 with Streaming bit set rather than WRITE10. Speeds up DVD-RAM. Might help with BD-RE. - This gets transferred to burn_drive.do_stream_recording */ + This gets transferred to burn_drive.do_stream_recording + */ int do_stream_recording; + /* ts A91115 : override value for .obs on DVD media. + Only values 0, 32K and 64K are allowed for now. */ + int dvd_obs_override; + + /* ts A91115 : size of the fsync() interval for stdio writing. + Values 0 or >= 32 counted in 2 KB blocks. */ + int stdio_fsync_size; + + /** A disc can have a media catalog number */ int has_mediacatalog; unsigned char mediacatalog[13]; @@ -64,6 +74,11 @@ struct burn_write_opts unsigned char multi; }; +/* Default value for burn_write_opts.stdio_flush_size +*/ +#define Libburn_stdio_fsync_limiT 8192 + + /** Options for disc reading operations. This should be created with burn_read_opts_new() and freed with burn_read_opts_free(). */ struct burn_read_opts diff --git a/libburn/write.c b/libburn/write.c index a89247a..3d8d8f6 100644 --- a/libburn/write.c +++ b/libburn/write.c @@ -1246,6 +1246,126 @@ int burn_disc_close_track_dvd_plus_r(struct burn_write_opts *o, } +/* <<< +#define Libburn_simplified_dvd_chunk_transactioN 1 +*/ + +#ifdef Libburn_simplified_dvd_chunk_transactioN + +/* ts A91114 : EXPERIMENTAL, NOT COMPLETELY IMPLEMENTED + + Simplified data transmission for DVD. libburn via Linux USB is 30 % slower + than growisofs or cdrecord when transmitting 32 KB chunks. + With 64 KB chunks it is 20% faster than the competitors. + No heavy CPU load is visible but there might be subtle race conditions in + the USB driver which work better with shorter time gaps between WRITE + commands. + + Insight: It is actually about the interference of track source reading + with SCSI writing via USB. growisofs reads with O_DIRECT into a + mmap()ed buffer. When doing the same, libburn with 32 KB chunks + reaches similar write speed. + On the other hand, 64 KB chunks are 20% faster than that and + are not improved by reading O_DIRECT. + + O_DIRECT is a property of the input fd of struct burn_source. + It can only be done with properly aligned memory and with aligned + read size. Alignment size is file system system specific. + System call + mmap(NULL, (size_t) buffer_size, PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, -1, (off_t) 0); + is supposed to allocate a properly aligned buffer. + 64 KB is supposed to be a safe size. + + @return 1= ok, go on , 2= no input with track->open_ended = nothing written + <= 0 = error +*/ +static int transact_dvd_chunk(struct burn_write_opts *opts, + struct burn_track *track) +{ + int curr = 0, valid, err; + struct burn_drive *d = opts->drive; + struct buffer *out = d->buffer; + unsigned char *data = out->data; + +#ifdef Libburn_log_in_and_out_streaM + /* <<< ts A61031 */ + static int tee_fd= -1; + if(tee_fd==-1) + tee_fd= open("/tmp/libburn_sg_readin", + O_WRONLY|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR); +#endif /* Libburn_log_in_and_out_streaM */ + + + /* Read a chunk full of data */ + + /* ??? Do we have offset padding ? >>> First produce offset padding */; + + /* <<<< */ + if (0 && !track->eos) { + for (curr = 0; curr < opts->obs; curr += 2048) { + if (track->source->read != NULL) + valid = track->source->read(track->source, + data + curr, 2048); + else + valid = track->source->read_xt(track->source, + data + curr, 2048); + if (valid <= 0) { + track->eos = 1; + break; + } + track->sourcecount += valid; + +#ifdef Libburn_log_in_and_out_streaM + if(tee_fd!=-1 && valid>0) { + write(tee_fd, data + curr, valid); + } +#endif /* Libburn_log_in_and_out_streaM */ + + } + } else if (!track->eos){ + valid = track->source->read(track->source, data, opts->obs); + if (valid <= 0) { + track->eos = 1; + } else { + track->sourcecount += valid; + curr = valid; + +#ifdef Libburn_log_in_and_out_streaM + if(tee_fd!=-1 && valid>0) { + write(tee_fd, data, valid); + } +#endif /* Libburn_log_in_and_out_streaM */ + } + } + if (curr == 0 && track->open_ended) { + + /* >>> allow tail padding */; + + return 2; + } + if (curr < opts->obs) + memset(data + curr , 0, opts->obs - curr); + + /* Write chunk */ + out->bytes = opts->obs; + out->sectors = out->bytes / 2048; + err = d->write(d, d->nwa, out); + if (err == BE_CANCELLED) + return 0; + track->writecount += out->bytes; + track->written_sectors += out->sectors; + d->progress.buffered_bytes += out->bytes; + d->nwa += out->sectors; + out->bytes = 0; + out->sectors = 0; + + return 1; +} + +#endif /* Libburn_simplified_dvd_chunk_transactioN */ + + /* ts A61218 - A81208 */ int burn_dvd_write_track(struct burn_write_opts *o, struct burn_session *s, int tnum, int is_last_track) @@ -1322,9 +1442,18 @@ int burn_dvd_write_track(struct burn_write_opts *o, d->progress.buffer_capacity / 2048 + 128; } +#ifdef Libburn_simplified_dvd_chunk_transactioN + + ret = transact_dvd_chunk(o, t); + if (ret <= 0) + {ret = 0; goto ex;} + i += o->obs / 2048 - 1; + d->progress.sector += o->obs / 2048 - 1; +#else /* transact a (CD sized) sector */ if (!sector_data(o, t, 0)) { ret = 0; goto ex; } +#endif if (open_ended) { d->progress.sectors = sectors = i; @@ -1789,11 +1918,22 @@ int burn_dvd_write_sync(struct burn_write_opts *o, /* <<< test only : Does this increase effective speed with USB ? ts A90801 : 64kB: speed with 16x DVD-R is 12 rather than 8 128kB: glibc complains about double free - BURN_OS_TRANSPORT_BUFFER_SIZE would need to - be enlarged anyway. + With BURN_OS_TRANSPORT_BUFFER_SIZE + enlarged to 128 MB, the first WRITE fails + with an i/o error. o->obs = 64 * 1024; */ + if (o->dvd_obs_override >= 32 * 1024) + o->obs = o->dvd_obs_override; + + if (o->obs > BUFFER_SIZE) { + sprintf(msg, "Chosen write chunk size %d exceeds system dependent buffer size", o->obs); + libdax_msgs_submit(libdax_messenger, d->global_index, + 0x00000002, LIBDAX_MSGS_SEV_DEBUG, + LIBDAX_MSGS_PRIO_ZERO, msg, 0, 0); + o->obs = BUFFER_SIZE; + } sprintf(msg, "dvd/bd Profile= %2.2Xh , obs= %d , obs_pad= %d", d->current_profile, o->obs, o->obs_pad); @@ -2043,8 +2183,6 @@ int burn_stdio_slowdown(struct burn_drive *d, struct timeval *prev_time, return 1; } -/* Flush write buffer after each 16 MB */ -#define Libburn_stdio_flush_limiT 8192 /* ts A70904 */ int burn_stdio_write_track(struct burn_write_opts *o, struct burn_session *s, @@ -2085,7 +2223,7 @@ int burn_stdio_write_track(struct burn_write_opts *o, struct burn_session *s, d->progress.sector++; /* Flush to disk from time to time */ if (d->progress.sector - prev_sync_sector >= - Libburn_stdio_flush_limiT) { + o->stdio_fsync_size && o->stdio_fsync_size > 0) { prev_sync_sector = d->progress.sector; if (!o->simulate) burn_stdio_sync_cache(d->stdio_fd, d, 1);