…e quando sono molti vanno “curvati” elettronicamente

Mi capita spesso, girando tra piazze e locali, di vedere band di vario genere e orchestre piazzare i subwoofer ai lati del palco, a volte li trovo distanziati in modo uniforme a coprire tutta la lunghezza, mentre raramente li trovo raggruppati al centro del palco stesso; già la vicinanza dei muri genera effetti deleteri, se poi ci aggiungiamo un posizionamento non corretto possono generarsi dei veri e propri disastri.

Vediamo adesso alcune configurazioni ed i loro comportamenti, tenendo come riferimento un passa alto del 4° ordine a 30Hz come protezione da eccessive escursioni ed un filtro a 100Hz sempre del 4° ordine (24dB/oct); configurazione abastanza diffusa per dei 18″.

1. 2 subwoofer ai lati del palco (molto diffusa, con anche 2 o 3 per lato)

Supponiamo un piccolo palco di 5m, e con una largheza di 60cm tipica di un subwofer da 18″ ci ritroveremo con i centri dei due altoparlanti a circa 5,6m uno dall’altro, che per comodità arrotondiamo a 6m, come nella figura

Studio_20190820_115813

Le X su un arco di 30° rappresentano una serie di microfoni piazzati per rilevare la risposta in frequenza.

Risultato? Un disastro…

La risposta rilevata dai microfoni diventa

Studio_20190820_120025

Giusto per fare un esempio, se ci trovassimo spostati di circa 20° rispetto al centro del palco ad una distanza di 15m avremmo un grosso buco localizato a circa 85Hz che è una zona molto energica.

Per dare una maggiore idea del “danno” ecco il grafico della dispersione a 80Hz

Studio_20190820_115915.png

Tra i 10m e i 15m c’è un ampia zona praticamente morta;il grafico polare alle varie frequenze che ci interessano diventa una cosa simile, con le varie frequenze che hanno i loro buchi ad angolazioni diverse, tutte nell’ordine di 12dB e più

Studio_20190820_120140.png

2. 4 subwoofer distanziati in modo uniforme a coprire la larghezza del palco (della serie te lo risolvo io il problema…)

In questo caso abbiamo 4 subwoofer distanziati 2m uno dall’altro in modo da coprire tutta la larghezza del palco; in pratica vengono aggiunti 2 sub centrali per cercare di rendere piu uniforme il fronte sonoro.

Studio_20190820_132006

In questo caso andiamo un po’ meglio rispetto a prima

Studio_20190820_132158.png

Ma tra i 25° e i 30° perdiamo tra i 9dB e i 15dB a 80Hz; anche il grafico della dispersione a 80Hz mostra ancora buchi “pesanti”

Studio_20190820_132109

Rispetto alla configurazione precedente abbiamo almeno il vantaggio di una più rapida attenuazione ai lati del palco, come conferma anche il grafico polare.

Studio_20190820_132249

3. Come il precedente ma con un po’ di ritardo applicato ai 2 più esterni

In questo caso la disposizione rimane come la precedente ma i due subwoofer piu esterni vengono ritardati di 2ms, molto semplice da fare con un crossover elettronico oppure dal pannello posteriore di molti box amplificati di attuale produzione.

La risposta in frequenza diventa

Studio_20190820_175349

Un ottimo passo in avanti rispetto alle 2 configurazioni viste sopra

La dispersione a 80Hz è un’ulteriore conferma

Studio_20190820_175443

E il grafico polare alle varie frequenze

Studio_20190820_175528

Ma se metto i 4 sub al centro del palco uno appiccicato all’altro?

4. 4 subwoofer affiancati

Supponiamo di predere i nostri 4 sub e unirli al centro del palco, togliendo anche il ritardo di 2ms visto prima.

Studio_20190820_181020

La risposta in frequenza diventa praticamente perfetta

Studio_20190820_181058

E anche il grafico della dispersione a 80Hz non è affatto male

Studio_20190820_181158

Idem il diagramma polare alle varie frequenze

Studio_20190820_181242

Se aggiungiamo i 2ms di ritardo visti prima abbiamo un ulteriore miglioramento che porta quasi alla perfezione.

Studio_20190820_182126

Il ritardo progressivo diventa poi obbligatorio se il numero di subwoofer affiancati è pari a 6 o piu; senza fare tanti calcoli vediamo cosa succede a 80Hz con tutti e 6 i box allineati, abbastanza bruttina

Studio_20190820_182624

e con la coppia mediana ritardata di 1ms e quella più esterna di 3ms, grafico molto migliore.

Studio_20190820_182943

Quindi sebbene i grafici visti fino a qui rappresentino una situazione ideale (no riflessioni, ecc), con quella reale che sicuramente è peggio possiamo comunque dire che:

  • È sempre meglio mettere i subwoofer allineati al centro del palco
  • Fino a quando sono al massimo 4 ritardare i piu esterni è una finezza
  • Oltre 4 diventa mandatorio impostare dei ritardi progressivi
  • Evitare il più metterli distanziati di 1,5m/2m uno dall’altro
  • Evitare di metterli ai lati del palco

C’è chi pensa che metendoli ai lati diano meno fastidio a chi c’è sul palco, non e vero; per ridurre la quantità di bassi sul palco, e anche per ridurre le riflssioni quando si ha dietro un muro, è necessaria una configurazione cardioide (che vedremo in seguito).

 

Since the installation of Sql Server 2016 Service Pack 1, on some of our customers with hi-end machines, we started seeing a couple of issues performance related, which sometimes caused the server to slow down, and in some circumstances almost hang. With the term hi-end I refer to boxes with more than 48 physical cores and an amount of RAM ranging from 1Tb to 2Tb, running at 40K batches/sec and more with a rate of several thousands of Sql Transactions/sec.

We never had such kind of issue with either 2014 or 2016RTM and in that period we were introducing further optimizations on both the Web code and the Stored Procedures, to further reduce resource utilization.

The faced issues basically were:

  • a huge amount of latch contention of type ACCESS_METHODS_ACCESSOR_CACHE, sometimes being the higher percentage of the day and with situations of many seconds of wait time,
  • Repeated episodes of heavy locks of type COMPILE, lastinng for 30/40s and even more
  • An increased CPU comsumption with the same load and usage pattern we were used to.

We started loking at the performance counters and found that the Plan Cache was always very low, around 1Gb for both Procedure and Ad Hoc, with an increased rate of Compilations/sec and Recompilations/sec over the past. Tried to investigate for an increased number of statistics update events but nothing, no apparent reasons for the continuous evictios from the Plan Cache; the Compile locks and the ACCESS_METHODS_ACCESSOR_CACHE latch were the results of the “hard work” of the engine over the Plan Cache.

So started looking at the RING_BUFFER_RESOURCE_MONITOR, thinking something like “ok, if it is a memory issue I should find something about it there…” and found this..

image005-2

Ok, system and process indicators were healthy, but the pool indicator was telling that some pool was suffering; how this can happen if the Plan Cache is already very low and the Buffer Pool was fine? That was my question…

So “asked” more details to the sys.dm_os_memory_clercks wich told

image006-2

So what??? 60Gb for the _XACT_CACHE and 14Gb for the _LOCK_MANAGER ? This is a 2Tb box, so we know that on this box the cache pressure limit is around 107Gb (75% of visible memory from 0 to 4Gb + 10% from 4Gb to 64Gb + 5% > 64b ) and that notifications are raised when a single cache store reaches 62,5% of the above calculations -> 67Gb, so we were roughly on that range. On the image You can also see the _OBJCP and the _SQLCP cache stores to be very low.

We issued a DBCC FREESYSTEMCACHE(‘All’) and after a while the result was

image002

The plan cache for object and adhoc quickly grew to the value we always saw in the past, the other cache stores greatly reduced their footprint and for some days we didn’t have neither notifications from the RING_BUFFER nor latches or compile lock.

To check the behavior of the _XACT_CACHE  and the _LOCK_MANAGER stores we started collecting the output of the sys.dm_os_memory_clercks every hour and quickly saw the tipical memory leak behavior.

This is the output of a second box with 1Tb RAM, with the collection started just before a DBCC FREESYSTEMCACHE; the plan cache slowly comes to a steady value and then when the CACHESTORE_XACT_CACHE comes to around 25Gb Sql starts kicking out plans and allowing less room for them; we then identified the “deeps”  of the graph to be in synch with our most evident issues.image008

This is the graph created on the 2Tb box wich shows that as soon the CACHESTORE_XACT_CACHE is reduced the plan cache starts growing in value.

image012

We decided to open a case with Microsoft support because it clealry seemed a memory leak, we never faced this issue till the installation of the SP1 for Sql 2016, and I never saw something similar during 15 years in the Sql Support Team…

MS told that nothing changed on that side starting with SP1 and suggested to try to implement Trace Flag 3920 to completely disable Transaction Cache; I’m not happy in completely disable it so by now we run DBCC FREESYSTEMCACHE(‘Transactions’) once a week and we don’t have those issues anymore.

However I still have my doubt for some regressions introduced by SP1…

Please feel free to contact me for further details or if you experienced a similar issue.

… when You can’t use InMemory

We read more and more on temporary tables and table variables, and the pro/cons of one over the other, and also some myths have been explained ( …both are on the tempdb ) ; to make it short, there are a couple of pro in favor of temp tables:

  1. Have statistics, while for table variables (also InMemory) SQL Server always estimates 1 row.
  2. Are accessible from stored procedures called inside the one that created the temp table.

Point 1 become negligible in case of objects with few rows, while in case of a great number of rows we can use:

  • OPTION (RECOMPILE), but particular attention may be needed in case of several calls (also every second), because You may spend more CPU resources in continuously recompiling the statements instead of run them.
  • TRACE FLAG 2453, but the setting is server wide, so the risk is to fall back on the situation mentioned above.

Given this let’s look at a more “practical” approach to this comparison, which basically take into account two fundamental key points for the TempDb performance when dealing with “High Workload Scenarios”:

  • PAGELATCH contention, EX and SH, on PFS pages ( 1 and every 8088 pages, 64Mb ), GAM and SGAM ( 2 and 3, every 511230 pages, 4Gb).
  • TempDb Tlog traffic, created by Log records, which translates into MB/s.

To show the differences I’ll use two stored procedures, one which creates a temporary table and the other which creates a table variable, inserting 5 rows each; their structure and average rows is very similar to that of our environments. An Extended Events session and a query over the TempDb Tlog will show the differences.


CREATE PROCEDURE [dbo].[proc_TestTemp]

AS

BEGIN

SET NOCOUNT ON

CREATE TABLE #Table1(

[Fld1] [bigint] NULL,

[Fld2] [int] NULL,

[Fld3] [int] NULL,

[Fld4] [tinyint] NULL,

[Fld5] [decimal](9, 2) NULL,

[Fld6] [decimal](9, 2) NULL,

[Fld7] [tinyint] NULL,

[Fld8] [varchar](15) ,

INDEX [IX_Fld1] CLUSTERED ([Fld1] ASC))       

INSERT INTO #Table1 VALUES (1,100000,200000,35,9.20,9.20, 3, 'Test')

INSERT INTO #Table1 VALUES (10,100000,200000,35,9.20,9.20, 3, 'Test')

INSERT INTO #Table1 VALUES (100,100000,200000,35,9.20,9.20, 3, 'Test')

INSERT INTO #Table1 VALUES (1000,100000,200000,35,9.20,9.20, 3, 'Test')

INSERT INTO #Table1 VALUES (1000,100000,200000,35,9.20,9.20, 3, 'Test')

END

GO       

CREATE PROCEDURE [dbo].[proc_TestVar]

AS

BEGIN

SET NOCOUNT ON

DECLARE @Table1 TABLE (

[Fld1] [bigint] NULL,

[Fld2] [int] NULL,

[Fld3] [int] NULL,

[Fld4] [tinyint] NULL,

[Fld5] [decimal](9, 2) NULL,

[Fld6] [decimal](9, 2) NULL,

[Fld7] [tinyint] NULL,

[Fld8] [varchar](15),

INDEX [IX_Fld1] CLUSTERED ([Fld1] ASC))

INSERT INTO @Table1 VALUES (1,100000,200000,35,9.20,9.20, 3, 'Test')

INSERT INTO @Table1 VALUES (10,100000,200000,35,9.20,9.20, 3, 'Test')

INSERT INTO @Table1 VALUES (100,100000,200000,35,9.20,9.20, 3, 'Test')

INSERT INTO @Table1 VALUES (1000,100000,200000,35,9.20,9.20, 3, 'Test')

INSERT INTO @Table1 VALUES (1000,100000,200000,35,9.20,9.20, 3, 'Test')

END

GO

The Extended Event session uses the sqlserver.latch_acquired event filtered for dbid 2 and the session from which I’m running the stored procedures.


CREATE EVENT SESSION [Latch]

ON SERVER

ADD EVENT sqlserver.latch_acquired(

ACTION(sqlserver.session_id,sqlserver.sql_text)

WHERE ([package0].[equal_uint64]([database_id],(2))

AND [sqlserver].[session_id]=(57)))

ADD TARGET package0.event_file(SET filename=N'Latch'),

ADD TARGET package0.ring_buffer(SET max_memory=(40960))

WITH (MAX_MEMORY=4096 KB,EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,

MAX_DISPATCH_LATENCY=1 SECONDS, MAX_EVENT_SIZE=0 KB,

MEMORY_PARTITION_MODE=NONE,TRACK_CAUSALITY=OFF,STARTUP_STATE=OFF)

GO

While the Tlog query is something like


SELECT

    fd.[Current LSN],

    fd.Operation,

    fd.AllocUnitName,

    fd.[Transaction Name],

    fd.[Transaction ID]

FROM sys.fn_dblog(NULL, NULL) AS fd

Putting all together and issuing a checkpoint before starting let’s check the results with the Temp Table…


USE tempdb

GO

CHECKPOINT

GO

ALTER EVENT SESSION Latch ON SERVER STATE = start

GO

exec [TestDb].[dbo].[proc_TestTemp]

GO

ALTER EVENT SESSION Latch ON SERVER STATE = stop

GO

SELECT

    fd.[Current LSN],

    fd.Operation,

    fd.AllocUnitName,

    fd.[Transaction Name],

    fd.[Transaction ID]

FROM sys.fn_dblog(NULL, NULL) AS fd

The Tlog query tells that there are 38 log records (138 at the first execution)

image

The Extended Events session show a total of 51 acquired Latchesimage

Let’s remove the just created files and repeat the same test with the Table Variable.

This time the query over the Tlog is telling that the number of records is 23 (240 at the first execution, meaning that caching a table variable creates more records)

image

The session shows now a total of 11 acquired Latches.

Cattura

Basically we have that Table Variables require much less Latch and Tlog records than Temp Tables, a condition that in case of thousands of calls per minute could make a great difference. If we change the Tlog query to extract the SUM ([Log Record Lenght]) we find that the sp using the Temp Table writes 5552 bytes, while the other 2632 bytes.

Let’s check now what happens on the Performance Counters “Log Flushes/sec” and “Log Bytes Flushed/sec” of the “Databases” object, tempdb instance; for the purpose I used the SQL Load Generator to generate (only) around 130 Batch/sec with the two stored procedure.

This is the result with the Temp Tables

image

16 Log Flushes per second and around 650Kb/sec of Tlog traffic.

On the contrary with the Table Variables we have

image

Almost half the  Log Flushes/sec ( 8 ) and the  Log Bytes Flushed /sec more than halved at 300Kb/sec.

So, from a practical point of view, when we can’t enable the InMemory feature, it is more useful to start playing with the table variables, particularly when we work with a small number of rows and several calls per minute (or second); and when the performance favors Temp Tables, and the rate is not so high, a RECOMPILE in the statement should eliminate any difference.

 

… quando non si possono usare le InMemory

Sulle tabelle temporanee e sulle variabili di tipo Table, e dei vantaggi e/o svantaggi delle prime rispetto alle altre, si è già scritto di tutto e di più, ed anche sfatati “strani” miti ( ma entrambe sono nel TempDb ); alla fine per farla breve rimangono a favore delle temporanee un paio di aspetti:

  1. Hanno le statistiche mentre per le variabili ti tipo table (anche InMemory) SQL Server stima sempre 1 riga
  2. Sono visibili da stored procedure richiamate da quella che ha creato la temporanea

Il punto 1 diventa trascurabile nel caso di oggetti con poche righe, mentre gli svantaggi con molte righe possono essere tranquillamente superati con:

  • OPTION (RECOMPILE), ma prestate attenzione al caso di numerose chiamate (anche ogni secondo), altrimenti si spreca più CPU per ricompilare gli statement che non eseguirli.
  • TRACE FLAG 2453, ma poi l’impostazione è per tutto il server, e per quanto riguarda la CPU si ricade nel punto precedente per tutte le stored procedure che usano variabili di tipo table.

Fatte queste premesse vediamo ora un approccio molto più pratico del confronto, che riguarda 2 aspetti fondamentali nelle performance del TempDb quando si ha a che fare con “High Workload Scenarios”;

  • PAGELATCH contention, EX e SH, nelle pagine PFS ( 1 e ogni 8088, 64Mb ), GAM e SGAM ( 2 e 3, e ogni 511230 pagine, 4Gb)
  • Traffico nel Tlog, generato dai record scritti, che alla fine si traduce in MB/s.

Per dimostrare le differenze userò due stored procedure che creano una tabella temporanea e una variabile di tipo table, inserendo 5 righe per ognuna; la loro struttura ed il numero di righe medie rispecchia una situazione tipica dei nostri ambienti; una sessione Extended Events e una query sul Tlog del Tempdb mostreranno le differenze.

CREATE PROCEDURE [dbo].[proc_TestTemp]
AS
BEGIN
SET NOCOUNT ON
CREATE TABLE #Table1(
[Fld1] [bigint] NULL,
[Fld2] [int] NULL,
[Fld3] [int] NULL,
[Fld4] [tinyint] NULL,
[Fld5] [decimal](9, 2) NULL,
[Fld6] [decimal](9, 2) NULL,
[Fld7] [tinyint] NULL,
[Fld8] [varchar](15) ,
INDEX [IX_Fld1] CLUSTERED ([Fld1] ASC))       

INSERT INTO #Table1 VALUES (1,100000,200000,35,9.20,9.20, 3, 'Prova')
INSERT INTO #Table1 VALUES (10,100000,200000,35,9.20,9.20, 3, 'Prova')
INSERT INTO #Table1 VALUES (100,100000,200000,35,9.20,9.20, 3, 'Prova')
INSERT INTO #Table1 VALUES (1000,100000,200000,35,9.20,9.20, 3, 'Prova')
INSERT INTO #Table1 VALUES (1000,100000,200000,35,9.20,9.20, 3, 'Prova')
END
GO       

CREATE PROCEDURE [dbo].[proc_TestVar]
AS
BEGIN
SET NOCOUNT ON
DECLARE @Table1 TABLE (
[Fld1] [bigint] NULL,
[Fld2] [int] NULL,
[Fld3] [int] NULL,
[Fld4] [tinyint] NULL,
[Fld5] [decimal](9, 2) NULL,
[Fld6] [decimal](9, 2) NULL,
[Fld7] [tinyint] NULL,
[Fld8] [varchar](15),
INDEX [IX_Fld1] CLUSTERED ([Fld1] ASC))

INSERT INTO @Table1 VALUES (1,100000,200000,35,9.20,9.20, 3, 'Prova')
INSERT INTO @Table1 VALUES (10,100000,200000,35,9.20,9.20, 3, 'Prova')
INSERT INTO @Table1 VALUES (100,100000,200000,35,9.20,9.20, 3, 'Prova')
INSERT INTO @Table1 VALUES (1000,100000,200000,35,9.20,9.20, 3, 'Prova')
INSERT INTO @Table1 VALUES (1000,100000,200000,35,9.20,9.20, 3, 'Prova')
END
GO

La sessione Extended Events usa l’evento sqlserver.latch_acquired filtrato per il dbid 2 e la sessione dalla quale si eseguono le due sp.

CREATE EVENT SESSION [Latch]
ON SERVER
ADD EVENT sqlserver.latch_acquired(
ACTION(sqlserver.session_id,sqlserver.sql_text)
WHERE ([package0].[equal_uint64]([database_id],(2))
AND [sqlserver].[session_id]=(57)))
ADD TARGET package0.event_file(SET filename=N'Latch'),
ADD TARGET package0.ring_buffer(SET max_memory=(40960))
WITH (MAX_MEMORY=4096 KB,EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,
MAX_DISPATCH_LATENCY=1 SECONDS, MAX_EVENT_SIZE=0 KB,
MEMORY_PARTITION_MODE=NONE,TRACK_CAUSALITY=OFF,STARTUP_STATE=OFF)
GO


Mentre la query sul Tlog è una cosa del tipo

SELECT
    fd.[Current LSN],
    fd.Operation,
    fd.AllocUnitName,
    fd.[Transaction Name],
    fd.[Transaction ID]
FROM sys.fn_dblog(NULL, NULL) AS fd


Mettendo tutto insieme ed eseguendo un checkpoint prima di iniziare vediamo cosa succede con la tabella temporanea…

USE tempdb
GO
CHECKPOINT
GO
ALTER EVENT SESSION Latch ON SERVER STATE = start
GO
exec [TestDb].[dbo].[proc_TestTemp]
GO
ALTER EVENT SESSION Latch ON SERVER STATE = stop
GO
SELECT
    fd.[Current LSN],
    fd.Operation,
    fd.AllocUnitName,
    fd.[Transaction Name],
    fd.[Transaction ID]
FROM sys.fn_dblog(NULL, NULL) AS fd

La query sul transaction log ci dice che sono stati scritti 38 log record ( 138 alla prima esecuzione )
image
Mentre per la sessione Extended Events sono stati acquisiti un totale di 51 Latch
image
Cancelliamo adesso i file della sessione Extended Events e ripetiamo la stessa cosa per la sp che usa la table variabile

Questa volta la query sul Tlog dice che i record scritti sono 23 ( 240 alla prima esecuzione, quindi mettere in cache una Table Variable genera più record)
image
Mentre la sessione Extended Events dice che i Latch acquisiti in totale sono solo 11
Cattura

 

Quindi in sostanza abbiamo che le variabili di tipo Table richiedono molti meno LATCH e record nel Tlog, condizione che nel caso di migliaia di chiamate al minuto può fare una differenza notevole. Se la query sul Transaction Log viene modificata per prendere una SUM ([Log Record Lenght]) abbiamo che la stored procedure che usa la tabella temporanea usa 5552 bytes, mentre l’altra 2632 bytes.

Vediamo adesso cosa succede prendendo come riferimento i contatori di Performance “Log Flushes/sec” e “Log Bytes Flushed/sec” dell’oggetto “Databases, istanza tempdb: a tal proposito ho configurato il tool SQL Load Generator per generare (solo) circa 130 Batch al secondo con le due stored appena viste.

Nel caso della stored procedure con tabella temporanea abbiamo il seguente risultato
image
16 Log Flushes al secondo e circa 650Kb/sec scritti nel tlog.
Passando alla varsione con variabile di tipo table otteniamo invece
image
I Log Flushes/sec sono dimezzati a 8 e i Log Bytes Flushed /sec più che dimezzati a 300Kb/sec.

Dal punto di vista pratico quindi,nel momento in cui non si possa abilitare l’ InMemory, è più conveniente affidarsi in prima istanza alle variabili ti tipo table, soprattutto quando si ha a che fare con poche righe e molte chiamate al minuto, e nei casi in cui la differenza di prestazioni volga a favore delle tabelle temporanee provare una RECOMPILE che molto spesso livella le prestazioni dei due oggetti.

 

In this article I’ll write nothing new regarding monitoring, but rather how to use what SQL Server already provide us and make it as light as possible; when working in “high OLTP workload” environments monitoring should be almost “invisible”, and by “high OLTP workload” I mean a server running at 50000/60000 Batches/sec

image

with the load made almost by stored procedures in the average CPU time from few ms to few tens of ms. Just for an example, the image below shows 10 minutes sampling taken at about 1/4 maximum load of one customer, with the first column showing the CPU time of every stored procedure over the total SQL Server CPU usage; so, if for example SQL was at 40% the first sp was responsible for the 19.8% of that load, and so on..

image

The above report is obtained from a table populated every minute with a simple query over the sys.dm_exec_procedure_stats

SELECT dateadd(mi, datediff(mi, 0, getdate()), 0), sql_handle,
plan_handle, total_elapsed_time, total_worker_time,
total_logical_reads, total_logical_writes, execution_count
FROM sys.dm_exec_procedure_stats

In addition to this, on our servers we usually capture every minute a snapshot over the sys.dm_exec_requests to get a photo of the running statements, and use it also in realtime when there is something that “smells” strange Sorriso; for this purpose we initially used the famous sp_WhoIsActive, very powerfull, but sometimes, when there were several process running or some blocking conditions, it happened that it was lasting too much or, never ending; sometimes it caused also an excessive latch contention on the tempdb and definitively slowed down the instance.

After digging a bit into the issue it came out to be the high usage of string manipulation functions which caused heavy usage of the TempDb and CPU time, that’s why the idea of something “lighter” and with only the functionality needed for our purpose.

Basycally we use a statement like this

SELECT s.host_name, r.session_id as 'session', r.blocking_session_id as [blocked by],
CAST  (SUBSTRING(st.text, (r.statement_start_offset/2)+1,
    ((CASE r.statement_end_offset
      WHEN -1 THEN DATALENGTH(st.text)
     ELSE r.statement_end_offset
     END - r.statement_start_offset)/2) + 1) as text) AS statement_text,  ISNULL(cast(OBJECT_SCHEMA_NAME(st.objectid, st.dbid) + '.' + OBJECT_NAME(st.objectid, st.dbid) as varchar(100)), 'AdHoc Statement') as object_name,
     s.login_name,
     CASE  WHEN LEFT(s.program_name, 8) = 'SQLAgent' then
                (SELECT 'SQLAgent Job: ' + b.name from msdb.dbo.sysjobs b WHERE (SUBSTRING(MASTER.dbo.FN_VARBINTOHEXSTR(CONVERT(VARBINARY(16), b.JOB_ID)),1,10)) = SUBSTRING(s.PROGRAM_NAME,30,10))
        ELSE s.program_name
    END AS [program_name],
r.start_time as request_start_time,r.last_wait_type,r.wait_time,
r.cpu_time, r.total_elapsed_time,
r.logical_reads, r.reads as physical_reads, r.status as request_status
FROM sys.dm_exec_sessions s left join sys.dm_exec_requests r on s.session_id = r.session_id
CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) AS st
WHERE r.session_id > 50 and r.session_id  @@SPID
AND last_wait_type  'SP_SERVER_DIAGNOSTICS_SLEEP'
ORDER BY cpu_time DESC

for cehcking in realtime what is currently running,  with an added

OUTER APPLY sys.dm_exec_text_query_plan( r.plan_handle,
r.statement_start_offset, r.statement_end_offset) tp

when we want to take a look at the Execution Plan ( CAST (tp.query_plan as xml) AS plan_xml in the fields list).

Second, we check for blocking processes with something like this

SELECT    s.session_id, r.blocking_session_id AS [blocked by], CAST(SUBSTRING(st.text, (r.statement_start_offset / 2) + 1,
                ((CASE r.statement_end_offset
                    WHEN - 1 THEN DATALENGTH(st.text)
                    ELSE r.statement_end_offset
                END - r.statement_start_offset) / 2) + 1) AS text) AS statement_text,
                ISNULL(cast(OBJECT_SCHEMA_NAME(st.objectid, st.dbid) + '.' + OBJECT_NAME(st.objectid, st.dbid)
                         AS varchar(100)), 'AdHoc Statement') AS object_name,
                s.login_name,
                CASE
                WHEN LEFT(s.program_name, 8) = 'SQLAgent' then
                        (SELECT 'SQLAgent Job: ' + b.name from msdb.dbo.sysjobs b WHERE (SUBSTRING(MASTER.dbo.FN_VARBINTOHEXSTR(CONVERT(VARBINARY(16), b.JOB_ID)),1,10)) = SUBSTRING(s.PROGRAM_NAME,30,10))
                ELSE s.program_name
                END AS [program_name], r.start_time AS request_start_time, r.last_wait_type, r.cpu_time, r.total_elapsed_time, r.logical_reads,
                r.reads AS physical_reads, r.status AS request_status, r.wait_time, r.command, master.dbo.fn_varbintohexstr(r.plan_handle) AS plan_handle
        FROM sys.dm_exec_sessions s
            LEFT JOIN sys.dm_exec_requests r
            ON r.session_id = s.session_id
            OUTER APPLY sys.dm_exec_sql_text(r.sql_handle) AS st
        Where  S.Session_ID In
            (
                 Select Blocking_Session_ID
                 From Sys.DM_Exec_Requests (READUNCOMMITTED)
                 Where Blocking_Session_ID  0
            )

Finally, becasue TempDb is a precious resource we introduced a check for long running transactions which can block the checkpoint process and cause a huge increase of the TLog size and, why not, exhaust the disk space. Just remember that on the TempDb the checkpoint happens when the TLog is at 70% usage and any open (long) transaction delay the process, and could start an “avalanche effect”; several times it does not depend on how much data You write in the TempDb but rather how much that transaction last

This script can also be changed for checking a different database name

SELECT  ISNULL(cast(tst.session_id as varchar),'Internal') as SessionID,
    tdt.database_transaction_log_bytes_reserved/1024 AS [TlogKB],
    tat.transaction_id AS [Transacton ID],
    tat.name      AS [TRANSACTION Name],
    tat.transaction_begin_time AS [TRANSACTION BEGIN TIME],
    DATEDIFF(mi, tat.transaction_begin_time, GETDATE()) AS [Elapsed TIME (in MIN)],
    CASE tat.transaction_type
        WHEN 1 THEN 'Read/write'
        WHEN 2 THEN 'Read-only'
        WHEN 3 THEN 'System'
        WHEN 4 THEN 'Distributed'
        END AS [TRANSACTION Type],
    CASE tat.transaction_state
        WHEN 0 THEN 'The transaction has not been completely initialized yet.'
        WHEN 1 THEN 'The transaction has been initialized but has not started.'
        WHEN 2 THEN 'The transaction is active.'
        WHEN 3 THEN 'The transaction has ended. This is used for read-only transactions.'
        WHEN 4 THEN 'The commit process has been initiated on the distributed transaction. This is for distributed transactions only. The distributed transaction is still active but further processing cannot take place.'
        WHEN 5 THEN 'The transaction is in a prepared state and waiting resolution.'
        WHEN 6 THEN 'The transaction has been committed.'
        WHEN 7 THEN 'The transaction is being rolled back.'
        WHEN 8 THEN 'The transaction has been rolled back.'
        END AS [TRANSACTION Description],
    CAST  (SUBSTRING(t.text, (r.statement_start_offset/2)+1,
    ((CASE r.statement_end_offset
        WHEN -1 THEN DATALENGTH(t.text)
        ELSE r.statement_end_offset
    END - r.statement_start_offset)/2) + 1) as text) AS statement_text
FROM sys.dm_tran_active_transactions tat
    INNER JOIN sys.dm_tran_database_transactions tdt
        on tat.transaction_id=tdt.transaction_id
    LEFT JOIN sys.dm_tran_session_transactions AS tst
        ON tdt.transaction_id = tst.transaction_id
    LEFT OUTER JOIN sys.dm_exec_requests AS r
         ON tst.session_id = r.session_id
    OUTER APPLY sys.dm_exec_sql_text(r.plan_handle) AS t
WHERE tdt.database_id=DB_ID('tempdb') and tdt.database_transaction_log_bytes_reserved > 0
ORDER BY 2 DESC     

Putting it all together I wrote a sp with 3 input parameters and named it sp_WhatIsRunning

USE master
GO
CREATE PROC [dbo].[sp_WhatIsRunning]
(
    @ShowPlan Bit = 0,
    @ShowLock Bit = 0,
    @ShowTempLog Bit = 0
)
AS
BEGIN
    SET NOCOUNT ON
    SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

    IF (@ShowPlan = 0)
    BEGIN
        SELECT s.host_name, r.session_id as 'session', r.blocking_session_id as [blocked by],
        CAST  (SUBSTRING(st.text, (r.statement_start_offset/2)+1,
            ((CASE r.statement_end_offset
             WHEN -1 THEN DATALENGTH(st.text)
            ELSE r.statement_end_offset
        END - r.statement_start_offset)/2) + 1) as text) AS statement_text,  ISNULL(cast(OBJECT_SCHEMA_NAME(st.objectid, st.dbid) + '.' + OBJECT_NAME(st.objectid, st.dbid) as varchar(100)), 'AdHoc Statement') as object_name,
        s.login_name,
        CASE  WHEN LEFT(s.program_name, 8) = 'SQLAgent' then
                    (SELECT 'SQLAgent Job: ' + b.name from msdb.dbo.sysjobs b WHERE (SUBSTRING(MASTER.dbo.FN_VARBINTOHEXSTR(CONVERT(VARBINARY(16), b.JOB_ID)),1,10)) = SUBSTRING(s.PROGRAM_NAME,30,10))
            ELSE s.program_name
        END AS [program_name],
        r.start_time as request_start_time,r.last_wait_type,r.wait_time,
        r.cpu_time, r.total_elapsed_time,
        r.logical_reads, r.reads as physical_reads, r.status as request_status
        FROM sys.dm_exec_sessions s left JOIN sys.dm_exec_requests r ON s.session_id = r.session_id
        CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) AS st
        WHERE r.session_id > 50 AND r.session_id  @@SPID
        AND last_wait_type  'SP_SERVER_DIAGNOSTICS_SLEEP'
        ORDER BY cpu_time DESC
    END
    ELSE
    BEGIN
    SELECT s.host_name, r.session_id as 'session', r.blocking_session_id as [blocked by],
    CAST  (SUBSTRING(st.text, (r.statement_start_offset/2)+1,
        ((CASE r.statement_end_offset
         WHEN -1 THEN DATALENGTH(st.text)
        ELSE r.statement_end_offset
        END - r.statement_start_offset)/2) + 1) as text) AS statement_text,  ISNULL(cast(OBJECT_SCHEMA_NAME(st.objectid, st.dbid) + '.' + OBJECT_NAME(st.objectid, st.dbid) as varchar(100)), 'AdHoc Statement') as object_name,
        s.login_name,
             CASE  WHEN LEFT(s.program_name, 8) = 'SQLAgent' then
                        (SELECT 'SQLAgent Job: ' + b.name from msdb.dbo.sysjobs b WHERE (SUBSTRING(MASTER.dbo.FN_VARBINTOHEXSTR(CONVERT(VARBINARY(16), b.JOB_ID)),1,10)) = SUBSTRING(s.PROGRAM_NAME,30,10))
                ELSE s.program_name
            END AS [program_name],         r.start_time as request_start_time,r.last_wait_type,r.wait_time,
        r.cpu_time, r.total_elapsed_time,
        r.logical_reads, r.reads as physical_reads, r.status as request_status,
        CAST (tp.query_plan as xml) AS plan_xml
        from sys.dm_exec_sessions s left join sys.dm_exec_requests r on s.session_id = r.session_id
        CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) AS st
        OUTER APPLY sys.dm_exec_text_query_plan( r.plan_handle, r.statement_start_offset, r.statement_end_offset) tp
        WHERE r.session_id > 50 and r.session_id  @@SPID
        AND last_wait_type  'SP_SERVER_DIAGNOSTICS_SLEEP'
        ORDER BY cpu_time DESC
    END

    IF (@ShowLock=1)
    BEGIN
        SELECT        s.session_id, r.blocking_session_id AS [blocked by], CAST(SUBSTRING(st.text, (r.statement_start_offset / 2) + 1, ((CASE r.statement_end_offset WHEN - 1 THEN DATALENGTH(st.text)
                         ELSE r.statement_end_offset END - r.statement_start_offset) / 2) + 1) AS text) AS statement_text, ISNULL(cast(OBJECT_SCHEMA_NAME(st.objectid, st.dbid) + '.' + OBJECT_NAME(st.objectid, st.dbid)
                         AS varchar(100)), 'AdHoc Statement') AS object_name, s.login_name,
             CASE  WHEN LEFT(s.program_name, 8) = 'SQLAgent' then
                        (SELECT 'SQLAgent Job: ' + b.name from msdb.dbo.sysjobs b WHERE (SUBSTRING(MASTER.dbo.FN_VARBINTOHEXSTR(CONVERT(VARBINARY(16), b.JOB_ID)),1,10)) = SUBSTRING(s.PROGRAM_NAME,30,10))
                ELSE s.program_name
            END AS [program_name]                         , r.start_time AS request_start_time, r.last_wait_type, r.cpu_time, r.total_elapsed_time, r.logical_reads,
                         r.reads AS physical_reads, r.status AS request_status, r.wait_time, r.command, master.dbo.fn_varbintohexstr(r.plan_handle) AS plan_handle
                        FROM sys.dm_exec_sessions s
                            LEFT JOIN sys.dm_exec_requests r
                            ON r.session_id = s.session_id
                         OUTER APPLY sys.dm_exec_sql_text(r.sql_handle) AS st
        Where  S.Session_ID In
            (
                 SELECT Blocking_Session_ID
                    FROM Sys.DM_Exec_Requests (READUNCOMMITTED)
                 WHERE Blocking_Session_ID  0
            )
    END
    IF (@ShowTempLog =1)
            BEGIN
            SELECT  ISNULL(cast(tst.session_id as varchar),'Internal') as SessionID,
            tdt.database_transaction_log_bytes_reserved/1024 AS [TlogKB],
            tat.transaction_id AS [Transacton ID],
            tat.name      AS [TRANSACTION Name],
            tat.transaction_begin_time AS [TRANSACTION BEGIN TIME],
            DATEDIFF(mi, tat.transaction_begin_time, GETDATE()) AS [Elapsed TIME (in MIN)],
            CASE tat.transaction_type
                WHEN 1 THEN 'Read/write'
                WHEN 2 THEN 'Read-only'
                WHEN 3 THEN 'System'
                WHEN 4 THEN 'Distributed'
                END AS [TRANSACTION Type],
            CASE tat.transaction_state
                WHEN 0 THEN 'The transaction has not been completely initialized yet.'
                WHEN 1 THEN 'The transaction has been initialized but has not started.'
                WHEN 2 THEN 'The transaction is active.'
                WHEN 3 THEN 'The transaction has ended. This is used for read-only transactions.'
                WHEN 4 THEN 'The commit process has been initiated on the distributed transaction. This is for distributed transactions only. The distributed transaction is still active but further processing cannot take place.'
                WHEN 5 THEN 'The transaction is in a prepared state and waiting resolution.'
                WHEN 6 THEN 'The transaction has been committed.'
                WHEN 7 THEN 'The transaction is being rolled back.'
                WHEN 8 THEN 'The transaction has been rolled back.'
                END AS [TRANSACTION Description],
            CAST  (SUBSTRING(t.text, (r.statement_start_offset/2)+1,
            ((CASE r.statement_end_offset
                WHEN -1 THEN DATALENGTH(t.text)
                ELSE r.statement_end_offset
            END - r.statement_start_offset)/2) + 1) as text) AS statement_text
        FROM sys.dm_tran_active_transactions tat
            INNER JOIN sys.dm_tran_database_transactions tdt
                on tat.transaction_id=tdt.transaction_id
            LEFT JOIN sys.dm_tran_session_transactions AS tst
                ON tdt.transaction_id = tst.transaction_id
            LEFT OUTER JOIN sys.dm_exec_requests AS r
                 ON tst.session_id = r.session_id
            OUTER APPLY sys.dm_exec_sql_text(r.plan_handle) AS t
        WHERE tdt.database_id=DB_ID('tempdb') and tdt.database_transaction_log_bytes_reserved > 0
        ORDER BY 2 DESC
    END
END     

You can call it simply with

  • exec sp_WhatIsRunning to get a list of running processes
  • exec sp_WhatIsRunning 1 to add the Execution Plan to the output
  • exec sp_WhatIsRunning 0,1 to show the list of running together with blocking/blocked processes
  • exec sp_WhatIsRunning 0,0,1 to show the list of running processes together with the open transactions list on the TempDb
  • exec sp_WhatIsRunning 1,1,1 to show all; running processes, blocked/blocking and TempDb active transactions

This is just a starting point, we created the sp this way because this is what we need for realtime monitoring, but the it can be expanded with additional fields and/or visualization options.

e come sempre alcune misure

Sebbene non sia mai stato un amante degli amplificatori in Classe D un po’ di tempo fa ho iniziato ad interessarmi dei moduli PowerSoft delle serie Digimod. l’idea era di utilizzare inizialmente un modulo Digimod 500 per un Subwoofer Home Theatre basato sull’altoparlante CIARE HS251, un 10” dall’ottimo rapporto qualità prezzo, e poi un modulo Digimod 1000 per un diffusore amplificato da impiegare anche come monitor, basato sul woofer 18Sound 12W500 in versione 4Ohm e Tromba 18Sound XR1064 pilotata da un driver RCF CD350. La scelta in questo caso è caduta su 18Sound per il fatto che il 12W500, nonostante l’elevata efficienza, non ha confronti in termini di estensione della risposta a parità di volume con altri modelli e/o marche, e perché la tromba è facilmente ruotabile di 90° per l’impiego come monitor e presenta una dispersione abbastanza ridotta su entrambe i piani per essere un componente “tradizionale”; ho scelto poi il  CD350 sinceramente per sperimentare cosa può essere in grado di fare un driver con bobina da 1,75” dal prezzo molto concorrenziale (69€ da www.rossinimusica.it).

Tornando ai moduli Digimod ho acquistato inizialmente il 500 da www.ggsound.it e successivamente i Digimod 1000 completi di Intergration Kit ed i cavi e gli accessori necessari alla programmazione tramite Armonia da laboratoriomusica.com di Vanis Dondi, dove ho trovato i prezzi migliori credo anche per gli altoparlanti 18Sound; Vanis inoltre è sempre stato molto gentile e disponibile sulle mie richieste di delucidazioni. Successivamente ho trovato altri 2 Digimod 1000 e due Digimod 1000NPS su Mercatino Musicale ad un prezzo molto vantaggioso.

I moduli permettono configurazioni molto flessibili in quanto praticamente tutti hanno a disposizione un connettore per collegare un modulo 1000NPS ed espandere cosi le possibilità di configurazione; il modulo DSP fornito con l’Integration Kit ha a disposizione una terza via sulle uscite 3 e 4 che permette di realizzare anche sistemi a 3 vie di notevole potenza, ad esempio con un 500 + 1000NPS oppure 1000+1000NPS con quest’ultimo ad esempio in bridge su 8Ohm.

Per quanto riguarda il loro impiego in campo professionale per quello che ne so, cercando un po’ qua e la nella rate, sono usati in diversi diffusori RCF oltre all’impiego in modo diffuso dei moduli IcePower della B&O; il DIGIMOD 1000 ad esempio è utilizzato nel TTL12-AS, mentre il TTS56-A usa 2 DIGIMOD 3000PFC.

Trattandosi naturalmente di moduli in classe D la potenza massima viene dichiarata nelle condizioni tipiche per questo tipo di configurazione, quindi con le specifiche EIAJ e all’ 1% di distorsione, come avviene anche per i finali di note marche; ma Powersoft in un documento reperibile online per questa linea “tradizionale” di moduli ha il pregio di elencare anche le potenze RMS erogabili dai moduli ed è a queste che farò riferimento nei miei test.

image

Notiamo quindi che per il più piccolo Digimod 500 si dichiara una potenza di 260W RMS con carico da 8Ohm e 450W RMS per 4Ohm, unitamente alla specifiche EIAJ un po’ più permissive; inoltre vengono riportati anche i limiti quando usato insieme ad un Digimod 1000NPS, al quale fornisce l’alimentazione.

Di seguito un paio di immagini del Digimod 500 montato sul dissipatore fornito insieme all’ Integration Kit, pronto per essere testato al banco.

20150604_193847

20150610_083146

Con il solito test 3s On e 15s Off a 100Hz il modulo in questione mostra ancora un’ onda pulita con 45.1V RMS con carico di 8Ohm, corrispondenti a 254W.

20150610_185227

I primi segnali di clipping arrivano a 46.4V corrispondenti a 270W

20150610_185354

L’onda è ancora molto “composta”, senza quel tipico taglio netto del clipping della maggior parte dei  finali tradizionali, e soprattutto molto simmetrico.

Passando a 4Ohm si nota che l’onda è ancora pulita a 41.1V RMS (l’immagine è un po’ mossa) corrispondenti a 422W RMS

20150610_190006

Mentre i primi segni del clipping si notano a circa 42.7V RMS, corrispondenti a 455W RMS, tra l’altro di nuovo con un principio di clipping molto simmetrico e abbastanza morbido; non sono in grado di misurarla ma con questa forma d’onda la distorsione è ancora molto bassa.

20150610_190046

Direi quindi un buon comportamento, considerando che si tratta di misure reali e non da laboratorio, quindi innanzitutto con tensione non stabilizzata e con cavo di alimentazione dell’ampli lungo circa 1,5m preso da un distributore di tensione che va alla presa a muro con un cavo da 3m , tutto con sezione di 2,5mm2.

A breve cercherò di pubblicare anche i test del modulo DIGIMOD 1000, unitamente a quelli con il 1000NPS ed in varie combinazioni; ad esempio, per simulare una tipico diffusore commerciale, una via che pilota un carico di 4Ohm (woofer) e l’altra che ne pilota uno da 8 o 16Ohm (Driver), con ad esempio una differenza di livello di 3/6dB tra le due vie che normalmente viene usata per compensare le differenze di efficienza unitamente all’equalizzazione.

Aggiornamento del 07/04/2017

In questi giorno sono riuscito a mettere un po’ al banco il DIGIMOD 1000, anche se al momento solo da solo e non accoppiato al modulo 1000NPS. Con il solito test ma con un periodo di ON un po’ più lungo del precedente, 4/5s contro 3s della precedente prova, ma sempre a 100Hz

Con un carico stereo da 8Ohm a 44V RMS (231W) per canale abbiamo ancora l’onda pulita nonostante il led del clipping sul modulo si sia già acceso: l’onda infine inizia a “piegarsi” poco oltre i 44V RMS (240W)

20170405_124610

Impostando invece uno dei canali con un livello di 3dB più basso  abbiamo l’onda ancora pulita a 44.3V RMS corrispondenti  a 245W, con l’altro canale che eroga poco più di 120W. Quindi ipotizzando di pilotare la classica configurazione MidWoofer+Driver tutto 8Ohm possiamo realizzare un diffusore/monitor da 300W RMS “reali” ed anche qualcosa di più, considerando che tra equalizzazione ed attenuazione di un driver da 1,75” la seconda via tipicamente erogherà da 1/2 ad 1/4 della potenza disponibile. Nonostante questo comunque consiglio di impostare il limiter della vie dedicata ai medioalti a circa 50W RMS che è anche la tipica potenza supportata da questo tipo di driver; per modelli invece con bobina da 2.5” / 3” tipicamente si viaggia tra i 90W e i 110W RMS.

Passando ai 2 canali a 4Ohm abbiamo l’onda pulita a 39,3V RMS corrispondenti a circa 386W RMS ed i primi segni di clipping a 40.3V RMS corrispondenti a circa 406W RMS; con questo test dopo circa 4s il limiter interno riduce la potenza RSM a circa 250W.

20170405_132746

20170405_133226

Impostando invece uno dei due canali con un guadagno a –3dB o –6dB rispetto all’altro i 40.3V RMS diventano puliti ed il clipping iniza ad apparire a circa 41V RMS (420W). Quindi nel caso in cui l’ipotetico due vie di cui sopra si ritrova con un MidWoofer da 4Ohm riusciamo a realizzare un sistema da 450W RMS reali con un driver da 1,75” e 500W nel caso di impiego di un componente con bobina da 2,5”/3”. Non ho provato la potenza in bridge su 8Ohm ma dal momento che abbiamo il dato in stereo su 4Ohm il conto è presto fatto.

Anche per il DIGIMOD 1000 quindi le specifiche sono confermate; a breve la prova de vari moduli combinati tra di loro.

Aggiornamento del 27/01/2018

In questi giorni sono riuscito a testare il DIGIMOD 1000 collegato al DIGIMOD 1000NPS, in configurazione bridge, quindi 2 canali da 8Ohm; in questa modalità i primi segni del clipping arrivano a 34.9V RMS per ramo, quindi 69.8V RMS totali, corrispondendti a crica 610W/8Ohm per canale, praticamente di nuovo in linea con le specifiche per quella configurazione (4 x 310W/4Ohm)

20170924_115722_001_1516997922078

20171119_185341_001_1516997921443

Ipotizzando quindi l’utilizzo di un DIGIMOD 500 collegato ad un 1000NPS i 3x 350W/4Ohm sono a tutti gli effetti un valore realistico, oppre 1 x 700/8Ohm (e anche più) + 1 x 230/8Ohm

Il finale Yamaha P7000S (review)

Pubblicato: 2 febbraio 2016 in Elettronica, Musica

E alcuni test…

Recentemente ho acquistato una coppia usata di finali Yamaha P7000s, in modo da pilotare 4 unità bassi, costruite con il woofer RCF L15P200AK-II; come ho fatto per altri finali in passato mi sono rivolto a Mercatino Musicale, dove li ho trovati in condizioni molto buone, ed ad un prezzo molto ragionevole, poco più di 700€ per entrambe. L’idea era di trovare una coppia di finali piùttosto che uno solo di maggiore potenza per avere maggiore flessibilità nella configurazione; li posso usare in stereo @8Ohm, o a ponte @4Ohm, ognuno che pilota una coppia di bassi. Inoltre, considerando che uso un Crest CC4000 sui mediobassi da 12”, sia a 8 che a 4 Ohm, posso provare cinfigurazioni differenti e ad esempio usare il CC4000 per pilotare i bassi in stereo @4Ohm e i due Yamaha sui 12”.

Anche per questo modello, come per il CC4000, ho letto numerosi commenti sia positivi che negativi sui vari forum; come al solito ho deciso con la mia testa e di provare. Uno sguardo agli schemi in rete ci dice che questo amplificatore ha:

  • un buon numero di transistor sullo stadio di uscita, 12 per canale; significa un buon fattore di smorzamento, meno potenza dissipata per transistor, ecc..
  • uno schema completamente a transistor per la sezione finale, con il tipico stadio di ingresso, filtri e “accessori” vari costruiti con integrati. Nella maggiore parte dei finali Pro lo stadio di ingresso della sezione finale è ad integrati; la serie P di Yamaha, come la serie CA di Crest, ha lo stadio finale completamente a transistor, con 1 solo condensatore sul percorso del segnale.
  • un interessante sistema di alimentazione (EEEngine) che sembra essere promettente in termini di potenza totale assorbita e dissipata, che si tradice in meno calore generato.

Un’ immagine dell’interno

P7000S Internal

Non sono ancora riuscito a trovare il tempo per effettuare dei test di ascolto e confrontarlo sia con il CA6 che con il CC4000, ma ho trovato un po’ di tempo per fare alcune prove al banco; ho usato come al solito il mio carico stereo da 8Ohm creato con 8 resistenze da 2Ohm 50W, che ha fronte dei 200W nominali per ramo è in grado di reggere 1000W con un “duty cicle” pari a 5 (1s ON, 5s OFF). Ho collegato il tutto ad un piccolo distributore di corrente a sua volta collegato alla presa di rete tramite una prolunga da 5m costruita con un cavo 3×2,5mm2, usando il cavo di alimentazione fornito, che trattandosi di uno 3×0,75mm2 sinceramente mi sembra un po’ striminzito e potrebbe mangiarsi qualche Watt (maggiori dettagli sulla review del CC4000). Magari ci torniamo in seguito.

Con il mio solito test da 3s on e 15s off @100Hz il P7000S clippa @675W/8Ohm, con il tester che segna 73,5V RMS, i led del clipping che iniziano ad illuminarsi e la forma d’onda come dall’immagine qui sotto.

100Hz full power

L’amplificatore quindi raggiunge pienamente le specifiche, che lo danno per 650W RMS nelle versioni per il mercato Europeo; le versioni EU (230V) infatti lasciano sul campo circa 50W rispetto alle altre, e dando un occhio allo schema questo è il risultato dell’utilizzo di un paio di induttori in serie all’alimentazione principale, il cui ruolo sinceramente non mi è molto chiaro, anche se su un forum ho letto che sembrerebbe trattarsi di una sorta di PFC, che normalmente è un po’ più complesso rispetto ad una semplice coppia di induttori.

Usando come riferimento un video visto in rete di un P7000S modificato, unitamente ad un check sullo schema che mi ha confermato che la loro rimozione avrebbe portato solo benefici (anche in termini di qualità probabilmente), mi sono deciso a scollegare i loro terminale sostituendoli con un ponticello di alcuni cm di cavo ed un paio di faston; le versioni non EU hanno un ponticello saldato direttamente sulla scheda ma il risultato è lo stesso.

Quindi l’ho provato di nuovo ed ho ottenuto circa 740W @8Ohm, con il tester che segna 77V RMS e i led del clip che iniziano a lampeggiare.

100Hz full power no coils

Come si vede l’onda è ancora “pulita”; sembra quindi che la rimozione delle bobine non solo regala qualche Watt in più (65W) ma sembra anche fornire un’alimentazione migliore ai moduli switching ed infine ai finali.

Ho ripetuto anche il test @50Hz ed il risultato è stato lo stesso, se non leggermente migliore.

50Hz full power no coils

Attualmente non ho a disposizione un numero di resistenze sufficiente per costruire un carico stereo da 4Ohm adeguato, quindi non riesco a provare amplificatori di questo taglio su quel carico senza il rischio di distruggere le resistenze, ma posso testare la configurazione a ponte @4Ohm con un minimo di margine; per questo amplificatore il datasheet riporta la potenza in bridge @4Ohm  (2Ohm stereo) solo per picchi di 20ms, ed il mio obiettivo era quello di avere un finale che configurato a ponte @4Ohm avesse le stesse caratteristiche del mio CA6 (adesso 1650W), con un minimo di margine; in questo modo quando sono utilizzati insieme forniscono almeno 3200/3300W e, cosa molto importante, senza spingere i finali al limite; attualmente con il CA6 che pilota due unità bassi e con 2 satelliti ottengo un buon bilanciamento globale, quindi con la configurazione finale da 4+4 mi viene garantito lo stesso bilanciamento, e un piccolo margine per “strafare” un po’.

Detto questo ho fatto alcune prove a ponte @4Ohm e alla fine ho deciso di fermarmi a circa 2350W RMS, 97V RMS; le due induttanza sono scollegate

4Ohm bridged

Questo è più che sufficiente per le mie esigenze,e la cosa positiva è che nessun circuir braker o altre forme di protezione/limitazione stavano intervenendo; mi preme solo ricordare che il CC4000 faceva scattare il suo circuit braker a circa 2100W @4Ohm a ponte, motivo per il quale avevo ridotto il ciclo ad 1s per potere raggiungere potenze superiori.

Come al solito ho fatto anche dei test a frequenza superiori per verificare l’assenza di artefatti dovuti ad una scarsa corrente di riposo e/o residui di alimentazione; questa volta inoltre ero ancora più curioso per il comportamento dell’EEEngine.

Questa è l’onda a 10KHz e 2.83V RMS

2.83V @10K

La stessa 10Kz a 80VPP (28,3V RMS, 100W/9Ohm)

20151122_163947_thumb2

Molto pulite entrambe; ho poi ripetuto lo stesso tests a 15KHz ma il risultato è stato lo stesso.

Aggiornamento dell’ 08/12/2015

Oggi ho sostituito il cavo di alimentazione con un pezzo di cavo da 3×2,5mm2, come si può vedere dalla foto del confronto con l’originale.

20151125_090105

I risultati alla fine sono rimasti gli stessi, con l’amplificatore che eroga 77,7V RMS (755W/8Ohm) ai primi segni del clipping, cosa che conferma che il P7000S, ed anche il suo fratello minore P5000S penso, abbia una sorta di “regolazione” dell’alimentazione in grado di reggere un minimo di “undervoltage”; la tensione sui connettori della scheda era circa 227V contro 222/223V rilevati con il cordone originale.

20151208_151946

Di seguito alcune letture prese dal distributore di alimentazione durante i test, giusto per avere un’idea del consumo di questo amplificatore.

A riposo, senza nessun’altra apparecchiatura collegata: 60VA

20151208_150243

100W RMS per canale @8Ohm, compresi circa 200VA usati da una lampadina, l’oscilloscopio, il pc ed il mixer; siamo quindi a circa 470VA totali.

20151208_151430

200W RMS @8Ohm entrambe i canali; circa 800VA

20151208_151615

Al clipping @8Ohm, sempre due canali funzionanti; poco più di 1900VA totali per circa 1500W sul carico.

20151208_151931